{ "cells": [ { "metadata": {}, "cell_type": "markdown", "source": "# Advanced Demo", "id": "b167ebc4245cb13c" }, { "metadata": {}, "cell_type": "markdown", "source": "The goal of this notebook is to demonstrate how ``GraPE-Chem`` for a more advanced workflow and in the context of hyperparameter optimization. Specifically, we will have a look at global features and demonstrating how we used the **BOHB** (Bayesian Optimization with HyperBand) by [1] as implemented in ``Ray-Tune``.", "id": "4da6634ab4d126b" }, { "metadata": {}, "cell_type": "markdown", "source": "## Using Global Features", "id": "61c84329e042ba3e" }, { "metadata": {}, "cell_type": "markdown", "source": [ "A global feature is a type of data that, in the context of molecules and graphs, describes extra, graph level information. Specifically, global features *are not* the target of whatever problem a GNN tries to solve. For instance, if we use the ``QM9`` dataset ([link](https://pytorch-geometric.readthedocs.io/en/latest/generated/torch_geometric.datasets.QM9.html)), we could use the *heat capacity* as our primary target and the *Dipole moment* as our global feature. These global features are then concatenated to the (last) latent representation of the GNN (after read-out). This simple introduction of the global features to the system has been shown to yield higher performance [2] without any new cost. \n", "\n", "In the following, we will train a simple MPNN on the QM9 dataset using the heat capacity as our target and and the Dipole moment as a global feature." ], "id": "1e25bfd0bab3bb09" }, { "metadata": { "ExecuteTime": { "end_time": "2024-06-04T14:12:53.019206Z", "start_time": "2024-06-04T14:11:31.310839Z" } }, "cell_type": "code", "source": [ "from grape_chem.datasets import QM9\n", "\n", "# The ids are based on the way it is stored in PyG\n", "data = QM9(target_id=5, global_feature_id=0)" ], "id": "17b9a615c98678b6", "outputs": [], "execution_count": 1 }, { "metadata": { "ExecuteTime": { "end_time": "2024-06-04T14:12:53.025396Z", "start_time": "2024-06-04T14:12:53.020397Z" } }, "cell_type": "code", "source": [ "print('Some example features:\\n')\n", "print('SMILES: ', data.smiles[:10], '\\n')\n", "print('Heat capacity: ', data.target[:10], '\\n')\n", "print('Dipole moment: ',data.global_features[:10], '\\n')" ], "id": "c4f99e4a27469702", "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Some example features:\n", "\n", "SMILES: ['C#C' 'C#N' 'C=O' 'CC' 'CO' 'C#CC' 'CC#N' 'CC=O' 'NC=O' 'CCC'] \n", "\n", "Heat capacity: [ 59.5248 48.7476 59.9891 109.5031 83.794 177.1963 160.7223 166.9728\n", " 145.3078 227.1361] \n", "\n", "Dipole moment: tensor([0.0000, 1.6256, 1.8511, 0.0000, 2.8937, 2.1089, 0.0000, 1.5258, 0.7156,\n", " 3.8266]) \n", "\n" ] } ], "execution_count": 2 }, { "metadata": {}, "cell_type": "markdown", "source": "To reduce the computation time for this example, we will only consider a subset of 3000 SMILES from QM9. However, one can just skip the following step if the whole dataset is to be used:", "id": "8fc799be0d3b73f6" }, { "metadata": { "ExecuteTime": { "end_time": "2024-06-04T14:12:54.368343Z", "start_time": "2024-06-04T14:12:53.026004Z" } }, "cell_type": "code", "source": [ "from grape_chem.utils import DataSet\n", "\n", "\n", "data = DataSet(smiles=data.smiles[:3000], target=data.target[:3000],\n", " global_features=data.global_features[:3000])" ], "id": "c699fe675609d9b4", "outputs": [], "execution_count": 3 }, { "metadata": {}, "cell_type": "markdown", "source": "We now prepare the data as usual:", "id": "5941504d0a1c5627" }, { "metadata": { "ExecuteTime": { "end_time": "2024-06-04T14:12:55.268228Z", "start_time": "2024-06-04T14:12:54.369144Z" } }, "cell_type": "code", "source": "train, val, test = data.split_and_scale(scale=True, split_type='random', seed=1234)", "id": "3040c854630c00e5", "outputs": [], "execution_count": 4 }, { "metadata": {}, "cell_type": "markdown", "source": "Initializing the model:", "id": "19a9e50b8f86bc8d" }, { "metadata": { "ExecuteTime": { "end_time": "2024-06-04T14:12:55.297922Z", "start_time": "2024-06-04T14:12:55.269889Z" } }, "cell_type": "code", "source": [ "from grape_chem.models import MPNN\n", "\n", "model = MPNN(node_in_dim=data.num_node_features, edge_in_dim=data.num_edge_features, num_global_feats=1)" ], "id": "1cb5cd995b706d55", "outputs": [], "execution_count": 5 }, { "metadata": {}, "cell_type": "markdown", "source": "**Note that we must now specify how many global features we are adding,** in addition to how many node and edge features we have. But the rest stays the same.", "id": "d18ef8f7dd625e76" }, { "metadata": {}, "cell_type": "markdown", "source": "Let us now specify all the required training elements:", "id": "782efdd2cb4bc244" }, { "metadata": { "ExecuteTime": { "end_time": "2024-06-04T14:12:55.301353Z", "start_time": "2024-06-04T14:12:55.298717Z" } }, "cell_type": "code", "source": [ "import torch\n", "from grape_chem.utils import EarlyStopping\n", "from torch.optim import lr_scheduler\n", "\n", "# optimizer\n", "optimizer = torch.optim.Adam(model.parameters(), lr=1e-3, weight_decay=1e-6)\n", "\n", "\n", "# Early stopper\n", "early_stopper = EarlyStopping(patience=30, model_name='best_model')\n", "\n", "# Learning rate scheduler\n", "scheduler = lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.9, min_lr=0.0000000000001, patience=15)" ], "id": "ebf013ec734007a5", "outputs": [], "execution_count": 6 }, { "metadata": {}, "cell_type": "markdown", "source": "We now train and plot the training/validation loss:", "id": "e9dc571ad546399" }, { "metadata": { "ExecuteTime": { "end_time": "2024-06-04T14:15:43.277623Z", "start_time": "2024-06-04T14:12:55.301948Z" } }, "cell_type": "code", "source": [ "from grape_chem.utils import train_model\n", "\n", "train_loss, val_loss = train_model(model = model,\n", " loss_func = 'mse',\n", " optimizer = optimizer,\n", " train_data_loader= train,\n", " val_data_loader = val,\n", " batch_size=300,\n", " epochs=300,\n", " early_stopper=early_stopper,\n", " scheduler=scheduler)\n", "\n", "model.load_state_dict(torch.load('best_model.pt'))\n", "\n", "from grape_chem.plots import loss_plot\n", "loss_plot([train_loss, val_loss], ['train loss', 'test loss'], early_stopper.stop_epoch)" ], "id": "2db9687f781c8d52", "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "epoch=298, training loss= 0.011, validation loss= 0.047: 100%|██████████| 300/300 [02:47<00:00, 1.79it/s]\n" ] }, { "data": { "text/plain": [ "
" ], "image/png": "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+/ev3da7d29uv/12Zs+ezQUXXMBbb71Vuy8xMZEbb7yRL7/8kr/97W/MmDGjTdvcHI+mOc444wzOOOOMFh8/ffp0unXrxjPPPAOYH8bvv//Of/7zHyZObP906qEK9jcff3FFy37hRURERERqJCUlsXjxYpKTkwkJCWm2YEOvXr348ssvmTRpEhaLhfvvv79VM0eNmTBhAoMGDeLyyy/nueeew263c/PNNzNu3DhGjBhBWVkZd955JxdddBHdunVj165dLF26lAsvvBCA2267jTPOOIPevXuTl5fH3Llz6devX5u2uTmHVTnyRYsWMWHChHrbJk6cyKJFizzUokMTbLMSWFmOo6gIDqD8pIiIiIjItGnTsFqt9O/fn9jY2GbHKz377LNERkYyZswYJk2axMSJEznmmGPatH0Wi4VvvvmGyMhITjzxRCZMmED37t355JNPALBarezdu5errrqK3r17c/HFF3PGGWfw8MMPA+BwOJg6dSr9+vXj9NNPp3fv3rzyyitt2uZm34/rQArGtyGLxcJXX33Feeed1+QxvXv35pprruGee+6p3TZr1izOOussSktLCQwMbPCaiooKKioqap8XFhaSmJhIQUEBYWFhrfoeDtSWHRn07tHBPCkuBs3ULCIiItKuysvL2blzJ926dSMgIMDTzZE20NzPuLCwkPDw8BbFBodVxulgPP7444SHh9cudat6eJqq6omIiIiIHB4Oq8ApISGh3kzDAJmZmYSFhTWabQK45557KCgoqF3qDk7ztJoxTgB2R9v2MRURERERkYN3WNXAHj16NLNmzaq37aeffmL06NFNvsbf3x9/L61YV3dm6JIKB+EebIuIiIiIiDTNoxmn4uJiVq1axapVqwBTbnzVqlW1A9vuuecerrrqqtrjb7zxRnbs2MFdd93Fpk2beOWVV/j000+5/fbbPdH8Q2bzdX/8JZV2D7ZERERERESa49HAadmyZQwbNoxhw4YBcMcddzBs2DAeeOABANLT0+tVB+nWrRszZ87kp59+YsiQITzzzDO88cYbh2Up8n2VVChwEhERERHxVh7tqjd+/HiaK+r39ttvN/qalStXtmGrPEMZJxERERER73VYjXE64lit/DZkHIXldiIUN4mIiIiIeC0FTp4UEMBzf3mM5Sl5TNePQkRERETEax1W5ciPRDUlyTXGSUREREQOF+PHj+e2227zdDPalQInDwvxN5PgaoyTiIiIiByItghepkyZwnnnndeq5zxSqH+YJ5WU8MoVIwB4fdxqDzdGRERERESaooyTlyhVxklEREREWmjKlCn8+uuvPP/881gsFiwWC8nJyQCsW7eOM844g5CQEOLj47nyyivJycmpfe3nn3/OoEGDCAwMJDo6mgkTJlBSUsJDDz3EO++8wzfffFN7znnz5rWoPXl5eVx11VVERkYSFBTEGWecwdatW2v3p6SkMGnSJCIjIwkODmbAgAHMmjWr9rWXX345sbGxBAYG0qtXL956661W+6xaizJOXqKkwuHpJoiIiIhIXZUlze+3+oO1+nbaXgnOqqaPtfiAX6BZd7mgqrT+flvwATXt+eefZ8uWLQwcOJBHHnkEgNjYWPLz8zn55JO57rrr+M9//kNZWRl33303F198Mb/88gvp6elceumlPPnkk5x//vkUFRXx22+/4XK5mDZtGhs3bqSwsLA2cImKimpRe6ZMmcLWrVv59ttvCQsL4+677+bMM89kw4YN+Pn5MXXqVCorK5k/fz7BwcFs2LCBkJAQAO6//342bNjA999/T0xMDNu2baOsrOyAPo/2oMDJSyhwEhEREfEyj3Vsfv/kt2HA+Wb9l0dg4YtNH9txGNwwz6yX7oWnetTf/1DBATUtPDwcm81GUFAQCQkJtdtfeuklhg0bxmOPPVa77c033yQxMZEtW7ZQXFyM3W7nggsuoGvXrgAMGjSo9tjAwEAqKirqnXN/agKmBQsWMGbMGAA++OADEhMT+frrr5k8eTKpqalceOGFtdfq3r177etTU1MZNmwYI0aYISxJSUkH9Fm0F3XV8xKqqiciIiIih2r16tXMnTuXkJCQ2qVv374AbN++nSFDhnDKKacwaNAgJk+ezIwZM8jLyzuka27cuBFfX19GjRpVuy06Opo+ffqwceNGAG699Vb+9a9/cfzxx/Pggw+yZs2a2mNvuukmPv74Y4YOHcpdd93FwoULD6k9bUUZJy+hqnoiIiIiXuYfe5rfb/V3r5/8AIy/p+ljLXXyFUHR+z/3QSouLmbSpEk88cQTDfZ16NABq9XKTz/9xMKFC5k9ezYvvvgi9957L4sXL6Zbt25t0iaA6667jokTJzJz5kxmz57N448/zjPPPMP//d//ccYZZ5CSksKsWbP46aefOOWUU5g6dSpPP/10m7XnYCjj5CWUcRIRERHxMrbg5hdrnRyEr635Y2vGNwFYLA33H0zzbDYcjvrDPY455hjWr19PUlISPXv2rLcEBwdXX97C8ccfz8MPP8zKlSux2Wx89dVXTZ5zf/r164fdbmfx4sW12/bu3cvmzZvp379/7bbExERuvPFGvvzyS/72t78xY8aM2n2xsbFcffXVvP/++zz33HO8/vrrB/x5tDUFTp5ktZI7bgK/dB9BUZXL060RERERkcNIUlISixcvJjk5mZycHJxOJ1OnTiU3N5dLL72UpUuXsn37dn788UeuueYaHA4Hixcv5rHHHmPZsmWkpqby5Zdfkp2dTb9+/WrPuWbNGjZv3kxOTg5VVc0UvKjWq1cvzj33XK6//np+//13Vq9ezRVXXEGnTp0499xzAbjtttv48ccf2blzJytWrGDu3Lm113zggQf45ptv2LZtG+vXr+e7776r3edNFDh5UkAAKe9+yp8nP0S+y+rp1oiIiIjIYWTatGlYrVb69+9PbGwsqampdOzYkQULFuBwODjttNMYNGgQt912GxEREfj4+BAWFsb8+fM588wz6d27N/fddx/PPPMMZ5xxBgDXX389ffr0YcSIEcTGxrJgwYIWteWtt95i+PDhnH322YwePRqXy8WsWbPw8/MDwOFwMHXqVPr168fpp59O7969eeWVVwCT5brnnnsYPHgwJ554IlarlY8//rhtPrRDYHG5XEdVqqOwsJDw8HAKCgoICwvzdHPYmlnEqf+ZT2SQHysfOM3TzRERERE5qpSXl7Nz5066detGQECAp5sjbaC5n/GBxAbKOHlYsL/pG6ty5CIiIiIi3kuBkyeVlNChUwwbnr0Qa1kplXanp1skIiIiIiKNUODkYZbSUoKqKgBV1hMRERER8VYKnLxIsQInERERERGvpMDJi2gSXBERERER76TAyYuoq56IiIiIiHdS4ORFilVZT0RERETEKylw8iLKOImIiIiIeCdfTzfgqObjA+PGsSmjCKfFouIQIiIiIiJeShknTwoMhHnzePGBGVT4+SvjJCIiIiJeYcqUKZx33nmeboZXUeDkBUJsJvFXWqkxTiIiIiLSMlOmTMFisTRYTj/9dE83DYBff/2Vk08+maioKIKCgujVqxdXX301lZWVALz99ttERER4tpEHQF31vECwv/kxqKue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o1J0D/PYTIGImnFO6/aoq56IiIiISFs7qMDp3HPP5d133wUgPz+fUaNG8cwzz3Deeefx6quvtmoDj2hVVfDyy2apqjNv03666oE7cNqaWUR5lQpEiIiIiIi0pYMKnFasWMHYsWMB+Pzzz4mPjyclJYV3332XF154oVUbeESrrIRbbjFLZaV7e+eRcO4rcOZTTb60Y3gAUcE27E4XmzWfk4iIiIhImzqowKm0tJTQ0FAAZs+ezQUXXICPjw/HHXccKSkprdrAo1JYBxh2OXQa3uQhFouFAR1NgYh1KhAhIiIiItKmDipw6tmzJ19//TVpaWn8+OOPnHbaaQBkZWURFhbWqg2Upg2qGee0W4GTiIiIiEhbOqjA6YEHHmDatGkkJSUxcuRIRo8eDZjs07Bhw1q1gUetdV/C11Nhy+wmD6ktELFbBSJERERERNrSQZUjv+iiizjhhBNIT0+vncMJ4JRTTuH8889vtcYd1VIWwqr3ISQWep/W6CE1GafNGUVU2p3YfA8qDhYRERERkf04qMAJICEhgYSEBHbt2gVA586dNflta4rqbh5zdzR5SOfIQEIDfCkqt7M9u5h+HdRNUkRERESkLRxUisLpdPLII48QHh5O165d6dq1KxEREfzzn//E6XS2dhuPTpFdzWN+WpOHWCwW+iWYYGljurrriYiIiIi0lYPKON17773897//5d///jfHH388AL///jsPPfQQ5eXlPProo63ayCOWvz989517va6ILuYxP7XZU/TrEMqS5FwFTiIiIiIibeigAqd33nmHN954g3POOad22+DBg+nUqRM333yzAqeW8vWFs85qfF94onkszYGKYvAPafSwmu55G9M1l5OIiIiISFs5qK56ubm59O3bt8H2vn37kpube8iNEiAwAgJM8QcKmu6u5w6cCnG5XO3QMBERERGRo89BBU5DhgzhpZdearD9pZdeYvDgwYfcqKNGVRW8/bZZqqoa7o+oGefUdHe9Pgmh+Fhgb0kl2UUVbdJMEREREZGj3UF11XvyySc566yz+Pnnn2vncFq0aBFpaWnMmjWrVRt4RKushGuuMeuTJ4OfX/39PU6G6B4QENHkKQL8rHSLCWZ7dgkb0guJCwtou/aKiIiIiBylDirjNG7cOLZs2cL5559Pfn4++fn5XHDBBaxfv5733nuvtdt49Dr1YZj8NnQZ1exhGuckIiIiItK2Dnoep44dOzYoArF69Wr++9//8vrrrx9yw6Tl+nUI47s16aqsJyIiIiLSRg4q4yTtxF4B6Wtg5/xmD+vXIRTQXE4iIiIiIm1FgZM327sNXhsLn17d7GE1XfV25JRQXuVoj5aJiIiIiBxVFDh5s5q5nMpyoaLp8UsJYQFEBPnhcLrYmlncTo0TERERETl6HNAYpwsuuKDZ/fn5+YfSFtlXQBgERkJZHuSnQXz/Rg+zWCz0Swhj0Y69bMwoZFDn8HZuqIiIiIjIke2AAqfw8OZvyMPDw7nqqqsOqUFHFX9/+PRT93pjIrpUB04pTQZOYOZzWrRjL9uylHESEREREWltBxQ4vfXWW23VjqOTr6+Zv6k5EV0gfXWzk+AC9IwLAWBrpkqSi4iIiIi0No1x8nYRXc3jfgKnXjWBkzJOIiIiIiKtToGTJ9nt8NlnZrHbGz+mNnBKafZUveJNSfJdeWWUVjZxLhEREREROSgHPQGutIKKCrj4YrNeXGy67u0root5LMps9lRRwTaig23sLalke1aJCkSIiIiIiLQiZZy8XbcTYdo2uHb2fg+tHeeUpXFOIiIiIiKtSYGTt7MFQUgsWCz7PbRXvMY5iYiIiIi0BQVOhwuXCypLmj2kV5wZ56RJcEVEREREWpcCp8PB6k/g6V4w665mD6uprLdNXfVERERERFqVAqfDQWAklGRD6sJmD+tZ3VUvNbeU8ipHe7RMREREROSooMDpcJA4ErBA7o5mq+vFhvgTHuiH0wU7spvv1iciIiIiIi2nwMmTbDZ46y2z2GxNHxcYAfEDzXozWSeLxVJnIlx11xMRERERaS0KnDzJzw+mTDGLn1/zx3YdbR5TFjV7WE1lvW2qrCciIiIi0moUOB0uulQHTvsb51RdWW9LpjJOIiIiIiKtRYGTJ9ntMHOmWez25o/tOsY8ZqyD8oImD+sTbwKnjekKnEREREREWosCJ0+qqICzzzZLRUXzx4YmQFR3wAVpS5s8bFCncMBU1ssvrWzFxoqIiIiIHL0UOB1OzngKbloIPU9p8pDwID+6RgcBsG53YXu1TERERETkiKbA6XDSawLEDwCLpdnDBlZnndbszm+HRomIiIiIHPkUOB2OXC5wVDW5e3B14LR2V9NjoUREREREpOUUOB1ulr8Dzw+BBc83ecigztUZJwVOIiIiIiKtwisCp5dffpmkpCQCAgIYNWoUS5YsadHrPv74YywWC+edd17bNtCbuByQnwJbfmzykJquervzy8gtUYEIEREREZFD5fHA6ZNPPuGOO+7gwQcfZMWKFQwZMoSJEyeSlZXV7OuSk5OZNm0aY8eObaeWeoleE83jrqVQnN3oIWEBfnSPCQZg7W5lnUREREREDpXHA6dnn32W66+/nmuuuYb+/fszffp0goKCePPNN5t8jcPh4PLLL+fhhx+me/fu7djaVmazwUsvmcVma9lrwjtBwmDABdt+avKwgbXjnPIPvZ0iIiIiIkc5jwZOlZWVLF++nAkTJtRu8/HxYcKECSxatKjJ1z3yyCPExcVx7bXX7vcaFRUVFBYW1lu8hp8fTJ1qFj+/lr+u9+nmcfF0qCpv9JDBGuckIiIiItJqPBo45eTk4HA4iI+Pr7c9Pj6ejIyMRl/z+++/89///pcZM2a06BqPP/444eHhtUtiYuIht9vjhl8NgZGQvhq+u81U2dtHzUS46qonIiIiInLoPN5V70AUFRVx5ZVXMmPGDGJiYlr0mnvuuYeCgoLaJS0trY1beQAcDpg3zywOR8tfF94ZJr8NFius/giWNAwiB3QKx2KB9IJyMgsbz0qJiIiIiEjL+Hry4jExMVitVjIzM+ttz8zMJCEhocHx27dvJzk5mUmTJtVuczqdAPj6+rJ582Z69OhR7zX+/v74+/u3QetbQXk5nHSSWS8uhuDglr+2+3g47V+w8j0zMe4+Qvx9GdQpnDW7Cpi/JZvJI46ATJuIiIiIiId4NONks9kYPnw4c+bMqd3mdDqZM2cOo0ePbnB83759Wbt2LatWrapdzjnnHE466SRWrVp1ZHTDOxDH3QTX/wJRjRfIGN87FoB5WxqvviciIiIiIi3j0YwTwB133MHVV1/NiBEjGDlyJM899xwlJSVcc801AFx11VV06tSJxx9/nICAAAYOHFjv9REREQANth8VLBbwC2xy97g+sbzwyzZ+25KN3eHE13pY9cwUEREREfEaHg+cLrnkErKzs3nggQfIyMhg6NCh/PDDD7UFI1JTU/Hx0Q1/k3J3wrafISAcBl9cb9fQxEjCA/0oKKtiVVo+I5KiPNRIEREREZHDm8XlaqQk2xGssLCQ8PBwCgoKCAsL82xjSkogJMSsH+gYpxprPoMvr4PEUXDt7Aa7b/lwBd+tSeeWk3oybWKfQ2ywiIiIiMiR40BiA6VyDncJ1V0UM9dDdaGMusb3iQNg3pas9myViIiIiMgRRYHT4S66F1j9obIY8pMb7B5XXSBi3e5CsopUllxERERE5GAocPIkPz948kmz+Pkd3DmsvhDX16xnrGuwOzbUn4GdTNrx182qriciIiIicjAUOHmSzQZ33mkWm+3gzxM/yDxmNgycAE7uawpt/Lg+4+CvISIiIiJyFFPgdCSoGefUSMYJ4OzBHQCYvyWHgrKq9mqViIiIiMgRQ4GTJzkcsHSpWRyOgz9PfE2BiLWN7u4dH0qvuBAqHU5+3pB58NcRERERETlKKXDypPJyGDnSLOWHULghfgCEdzFd9hz2Rg85qzrrNHNt+sFfR0RERETkKKXA6UgQFAW3r4VLPzTFIhpx1iATOP22NZuCUnXXExERERE5EAqcjhK94kPpEx9KlcPF7A0qEiEiIiIiciAUOB1JCvfA4tfA5Wp0d013vf+tUXc9EREREZEDocDpSGGvhFeOg+/vgpSFjR5yzpCOgOmul7q3tD1bJyIiIiJyWFPgdKTwtUH/c836yvcbPSQpJpixvWJwueD9xSnt2DgRERERkcObAqcjydArzOOGr6GiqNFDrhqdBMCny9IorzqEEugiIiIiIkcRBU6e5OcHDz5oFj+/Qz9f4kiI7gVVpbD+q0YPOblvHJ0iAskvreLb1XsO/ZoiIiIiIkcBBU6eZLPBQw+ZxWY79PNZLDDscrO+7K1Gi0RYfSxccVxXAN5dlIyriUISIiIiIiLipsDpSDP0CrD6w54VkLqo0UMuOTYRm68P63YXsi2ruJ0bKCIiIiJy+FHg5ElOJ6xfbxans3XOGRILQy816wtfavSQqGAbQzqHA7BuT0HrXFdERERE5AimwMmTyspg4ECzlJW13nlH3wI9J8CoG+pvL8qAl0fBnH/Sv0MYABvTGy8iISIiIiIibr6eboC0gZhecMUXDbcveB6yN0H2JvqdeTUAG/YUtnPjREREREQOP8o4HQ2c1WXHT7q3dtOgaFMUYkN6oQpEiIiIiIjshwKnI1ny7/Dm6TD/KfPcPwTCOgPQ02c3PhbILakkq6jCg40UEREREfF+CpyOZMWZprLektchP82UJ4/pBYB/3jZ6xIYA6q4nIiIiIrI/CpyOZP3OhfAuULoXXhgKzw8xk+MC5GyhX3WBiA3pCpxERERERJqjwOlIZvWF0TebdacdCndDr9PM8+wt9O+owElEREREpCVUVc+T/Pxg2jT3elsYdgXMexzKC6DbOOhynNmes4V+x1aXJFdXPRERERGRZilw8iSbDZ56qm2v4R8KY6fBT/fDyBug4zD4y3yI7kX/CisAO/eWUFppJ8imXwcRERERkcaoq97R4Phb4d4M6HM62IKhwxCwBREb6k9sqD8uF2zK0ES4IiIiIiJNUeDkSU4nJCebxels22v5BTa6uaZAxEaNcxIRERERaZICJ08qK4Nu3cxSVtZ+113+Nkw/AX57lkGdTOC0eEdu+11fREREROQwo8DpaFRRBBlrIWMNJ/eNA2Du5iwq7W2c9RIREREROUwpcDoaxfQxj9lbGJoYSUyIP0Xldhbv3OvZdomIiIiIeCkFTkej2N7mce82rDg5tb/JOs1en+nBRomIiIiIeC8FTkej8ETwDQBHBfz3NK72n48PTn7akInT6fJ060REREREvI4Cp6ORjxWOuxksVti9jL5L7+U+/0/IKCxn7e4CT7dORERERMTrKHA6Wk14EO7YCOPuBv8wImM6APDTBnXXExERERHZlwInT/L1hZtvNouvb/tfPzQext8Dt6/DZ+xtAMxal47Lpe56IiIiIiJ1eeBuXWr5+8PLL3u2DRYLBIRzct8ggmxWdmSX8MeOXEb3iPZsu0REREREvIgCJwEg1FXCyx1mkbk7hXcXJShwEhERERGpQ4GTJ7lckJNj1mNiTPbHU/JTGJ/5LhZfFys29WVPfn86RgR6rj0iIiIiIl5EY5w8qbQU4uLMUlrq2bZ0GILlpH8A8Ij1v/z0y8+ebY+IiIiIiBdR4CRuY6eRnXAiAZYqTl4zjYqSPE+3SERERETEKyhwEjcfHyIvf4t0Ykgkg7RP7254zMIX4dUToDir/dsnIiIiIuIhCpykHt/QGJYO/RcAPVM+wZX8u3tnaS7Mvg8y18Lqjz3UQhERERGR9qfASRoYd9pFfOo6BYDSr/4KTqfZsfI990HDrvBAy0REREREPEOBkzQQHuTH9qF385PjGB4NmAY+PuB0wNI3zAHnvAhBUZ5tpIiIiIhIO1I5cmnUFeMGMW7JNJwpcFVGIX3zf4P8VAiMhEGTPd08EREREZF2pYyTJ/n6wtVXm8XXu2LYxKggTh+YAMBjMzfCx5eZHQMugB/ugfcvdHfhExERERE5wnnX3frRxt8f3n7b061o0m0TejNnYxax278EW/XGMbfAS8eC0w5F6RDeyaNtFBERERFpD8o4SZN6x4fy0DkD+Mp5As/ZLyL5hCchqjtEdDUH5G73bANFRERERNqJAidPcrmgpMQsLpenW9OoPx2byFlDOvOc/QKuXNGL8ioHRPcwO/du82zjRERERETaiQInTyothZAQs5SWero1jbJYLDx2/kA6hgeQllvGjPk7IKomcFLGSURERESODgqcZL9CA/z4+5n9AHhl3nYKg7qYHbk7PNgqERHZr/xU+P5uyEv2dEtERA57CpykRSYN7sCIrpGUVTn4YJuf2aiMk4iId/v8Wlg83VRCFRGRQ6LASVrEYrHw4KQBWCy4A6e8nWZiXBER8U57VprHwj2ebYeIyBFAgZO02KDO4fzp2ET2uKKZ53McFcOvB3t521xs8Wvw+Z8hZVHbnF9E5GjQ53TzeOojnm2HiMgRQIGTHJB/nNmPTlHBTCm9lXuKLwZbcNtcaOd8WPcFZK5rm/OLiBwNyvLNY2CkR5shInIkUOAkByQ0wI//XDwUHwt8uWIXK354B6afAB9Mbr1ue+UFsOk7s164u3XOKSJyNCrPN4+Fe6CqzKNNERE53Pl6ugFHNasVLrrIvX6YGJEUxR2jw+m79D6O+aO6/3zGWkhZCN3G1j9460/mP+v+57T8Avmp7nX1yxcROXjlBebxp/uh6/HQebhn2yMichjziozTyy+/TFJSEgEBAYwaNYolS5Y0eeyMGTMYO3YskZGRREZGMmHChGaP92oBAfDZZ2YJCPB0aw7IVQkpTLCaoKkqqrfZuPaz+gdt+NZkoj69ErK3tPzkxVnudQVOIiIHr6zAvZ6f7LFmiIgcCTweOH3yySfccccdPPjgg6xYsYIhQ4YwceJEsrKyGj1+3rx5XHrppcydO5dFixaRmJjIaaedxu7d6tLVnsKGX8LTUQ8zsvxlvu9yh9m44RuwV5j1XcvhyxsAl3m+b1DVnJJs93rBrlZpr4jIUenSj8AWatbrZvNFROSAeTxwevbZZ7n++uu55ppr6N+/P9OnTycoKIg333yz0eM/+OADbr75ZoYOHUrfvn154403cDqdzJkzp51bfpSz+tJx1AVkEckbqR0gJMH0pd82x0y0+NGfwF4GYZ2h03CI7tnyc++bcXK5Wrv1IiJHh6Tj4bgbzXpeimfbIiJymPNo4FRZWcny5cuZMGFC7TYfHx8mTJjAokUtK0NdWlpKVVUVUVFRje6vqKigsLCw3uI1SkrAYjFLSYmnW3PAJg6Ix+pjYc2eEgp6ngsdhkBxJrxzDpRkQfxAmPoHXP8LDLmk5ScuznSvOyqgNLf1Gy8icrSI6GoelXESETkkHg2ccnJycDgcxMfH19seHx9PRkZGi85x991307Fjx3rBV12PP/444eHhtUtiYuIht1uM6BB/xvSIBuCDsD/DX+aDowryUyCyG1zxBfiHHviJ63bVG3o5OO0tf63TCRXFB35NEZEjTe4O+OpGWP2ReZ6vjJOIyKHweFe9Q/Hvf/+bjz/+mK+++oqAJoor3HPPPRQUFNQuaWlp7dzKI9vZgzsA8OWqTIrKq2DUDXDm03DVNxCaYA5yOs28TLPuAkcLgqCarnrnTYfzXoHQ+OaPr2vuv+CJrpC29ADfiYjIESY/zQRNe1a6nzudnm2TiMhhzKOBU0xMDFarlczMzHrbMzMzSUhIaPa1Tz/9NP/+97+ZPXs2gwcPbvI4f39/wsLC6i3Sek7rn0CQzcq2rGJO+898vl29hx+CzubtDU4+X76LhdtyKCgph0+vhiWvwY65+z9pYIQZMxXa/O9Ao357xmSoPpty4K8VETmS1MzhFNcfLFbT9bk4s9mXiIhI0zw6j5PNZmP48OHMmTOH8847D6C20MMtt9zS5OuefPJJHn30UX788UdGjBjRTq2VxkQG23jnzyOZ9tlqUvaWcutHKxscEx7ox9wB5xG17k348V5IGgt+zZRfn/y2eSzJgZRFprtfwsCWNejs5+C726it5icicrSqmcMpOAau/QnCOkDIAWTwRUSkHo931bvjjjuYMWMG77zzDhs3buSmm26ipKSEa665BoCrrrqKe+65p/b4J554gvvvv58333yTpKQkMjIyyMjIoLhY41o85dikKL7/61iuH9uNrtFBDOsSwRkDExjbK4aEsAAKyqq4dMs4HEGxkLMZfn2iZSde+R68dTosfLHljelXPdFu4e761flERI42ZfnmMSDcTHwb1hF8PP7fvojIYcujGSeASy65hOzsbB544AEyMjIYOnQoP/zwQ23BiNTUVHzq/EP/6quvUllZyUUXXVTvPA8++CAPPfRQezZd6giy+XLvWf2596z+9bYXlFZx/qsL2Jxdwr9jbuBeHoUFz0P/c6DjsIYnctihqpSftpdSthPOARMEtVRwNMQPgsy1kPwbDLzwkN6XiMhhq6arXkCEJ1shInLE8HjgBHDLLbc02TVv3rx59Z4nJye3fYPai9UKZ57pXj8ChQf58daUYzn/lYXMyBnAn7qcRo+s2fD93+HaHxu+IHsjTD+BQcTy14obOccfM5dTS2Ssg2//zwRNYApSKHASkaNVTVe9gHDYNAv+eAU6HwsTHvRsu0REDlPK2XtSQADMnGmWJqoCHgm6Rgdzy0lmAtznfK8Biw+k/QG5OxseXN29Lt8ZwB6q5+Zq6SS4+SmwZ4X7+c75h9p0EZHDV01XvcAIqCg0WfjdyzzZIhGRw5oCJ2kXY3vFADA71YIjaSz4+LlL5NZVHThluSLIckWabfYyKMvb/0VqMlPdToSo7tD1eLBXtkbzRUQOP/H9oftJENUDIrqYbXmay0lE5GB5RVc9OfL1jAshLtSfrKIKVg+6n2Mu7gmBkQ0PLDGBUw7hVGAjxxVGjKXQjHMKimr+IkXp5jGmD1z9v1Z+ByIih5mxfzMLQF6yeSzONBl8i8VjzRIROVwp4+RJJSUQHGyWkhJPt6ZNWSwWTuhpsk4/Z4U2HjRBbcYp2xUOQIarTne9/SmsDpzCOhxSW0VEjjjBcebRXg4VRZ5ti4jIYUqBk6eVlprlKHB8deC0YFuO2VBRDBlr6x9UHTjluMKx+lhId0VXb2/BpI1F1cFVaEfzjWr2Zlj6RsvGR4mIHGnSV8Pe7eCoAlsQ2ELMdk3VICJyUBQ4SbupCZzW7C6gaNtCeLoXfHSZKUFeo8QdOJ3cN467q65nYtDHcMxV+79A3YyToxJeGwcz/wZZG1r7rYiIeDeXC96YAC8eA0UZZltIddapRIGTiMjBUOAk7SYhPICecSG4XLCwuAP4+EJBKrx3nvsb0JquekRw0fDOFPiEsznXya68FmTlasY4hXYEX39IOsE83zan9d+MiIg3qyozXyCBqaoHlPhVd31WxklE5KAocJJ2VTPO6dedxXD+dPALNiVyXzsR9qzEcc4r3Gz/G+udXenfIYwhnc1YpzVrVsGXN0BlEwGU0wlj/g+GT4GwjmZbz1PM43YFTiJylKmZw8liBVsIu/PLeHLXAD7xv9BUHRURkQOmwEna1Ym9TeD06dI0vq0YBjfMNVXwitLh3fPIKXMwyz6cYms4HSMCGdMjBh+cDF9wA6z5BGZNa/zEPj4w7i6Y9Dz4V/fj73GyeUxZ1HTAdaC2zTHjBkREvFl5vnkMCAeLhY17CnnHMZF/FF2EI36QR5smInK4UuAk7Wp87zjOH9YJu9PFXz9eyUc7A+G6n81s9uX5RH0+mV6WXXSODMLqY+GEXjE48eF++7W4LD6w6gPYtbxlF4vpDWGdwVEBKQsOvfHpa+D9C0x2zOk49POJiLSVmoxTdTe9lFzz5ZHD6WJvSYWHGiUicnhT4ORJPj4wbpxZfI6OH4WPj4VnJg/h8lFdcLngni/X8tXGQrj8c4jqgV9FLpdY59IlKgiAY7pEEmyzMru0N/k9LzAn+eWRhifOXA8rP6g/qa7FAj2rs07bfzn0xm/5wb1eln/o5xMRaSs1/0YFmO7OabmlxJHHmT5/ULpulufaJSJyGDs67ta9VWAgzJtnlsBAT7em3fj4WPjXeQO55vgkAO78bA3z06rgup9ZF3M6210d6RptAiebrw+je5juff+LvAp8/GDHPNg5v/5Jt/wI39wMi1+rv71H9Tin1igQsXW2eTz7OQiOPvTziYi0ldquehEApOwtYZjPNl6xvUDk0uc81SoRkcOaAifxCIvFwv1n9eecIR2xO13c+P5y1uVZeTXybj5ynFKbcQIYVz0u6rs0Gwy/2myc88/68zPVVtQzk986nC4+XZpGWsRI841rx2FmLpODVZwNu5aZ9d6nH/x5mvPmGaZ88L5zW4mIHKiarnrVGaeU3NLaicWtZTmeapWIyGHN19MNkKOXj4+FpycPIbekkt+35XDzByvwtVoA6BodXHvcib1jAViRkkfxhbcRsvID2LUEVr7nnt+psHry2+qKeu//kcKD367nuO5RfHzndrD6HVpjt/4IuKDDUFPqfOdv0G3soZ2zLocdUhea9U+vgltXNn+8iEhzhl4OPSeA1Q+n08Wu3DKqMIGTf0WO+eLJYvFwI0VEDi/KOHlSSQnExpqlpMTTrfEIm68PL192DJ0iAknNLWVHtvkckqLdGaeu0cF0jQ7C7nSxMNMPxt1pdpTU+da0TsbJ5XLx/h8pACxNzqPwQBNNS/9rJs9NWejetvl789jlOHiyG7xzduuOc8pPca8XZdbPpomIHCj/EIjuARFdyCgsp9LhJKc64+TnrIDKYg83UETk8KPAydNycsxyFAsP8uOFS4dh9XF/+5lYp6sewIm9TNZp/tZsOP52uPZnGHuH2VleUCfj1IGlyXlszTI3BQ6ni4XbckyQtfS/sHd7841JWWiCpPRVsO4Ls62qHLbPNetDLoXIJLO+u4XV/Voie5N7vaoEyvJa79wiclRL2Wsq6pURQInL32zUJLgiIgdMgZN4heFdI/nbab0B6BIVRICftd7+mu56P2/IotTuhMRj3Ttn318n49SRDxab7I1vdSD265Zs+PZWmHkHrPqw6UY4HfDhJbDtJ/N8wzemC53VBlP+B6c8AB2GQOeRZv+upYf4ruuoGzgB5O1svXOLyNFn9n3w7nmw/RdSc00m39fHUpt1oiTbc20TETlMKXASr3HjiT144sJB/OeSoQ32Hd8zmrhQfzIKy7nv63W46nZly1hjHsM6kWuJ4Pu1GQD89ZReAMzfkoNrwPnmmHVfNN0NLnMdVBSCX5CpRFWSDcm/mVLxnYbD2L+ZMQGdq4O2xgKn4mz46UEz15TLZQKvlsjeXP95Xkrjxx2K5e/A4tdb/7yHO4fdZCNztnq6JSKtZ/dK2DEXyvJIrZ7DaVDncHKqxzkp4yQicuAUOInX8PGxcMmxXRjeNbLBviCbLy9cOgwfC3y5YjefLdvl3nntz3Dj73DDPD5fuYdKh5NBncK5bmx3bL4+7M4vY0f0iSYgytsJaYsbb0DNmKaux0NNoPXeeVCxz1iAxDqBk9NZf9/mWbDgOXjjZHh9HCx9o2VvviZwsoWYx/xWDpxKc+F/t8L3d0LOttY9N0DyAvhnLCx7s/XP3dZWvGOyka+O8XRLRFpPnXLkNV31jk2KIscVTpErEEfF0TmuVkTkUChwksPGcd2j+dtpfQC4/5t1ZuwSgNUXEgZRERDNWwuSAbh8VBcCbVZGdYsCYN7OUuh7tjn+kytgz6qGF0hZYB67joGBF7q3vz4O7JWUVzn4+xdrmLE5EHwDzdiqnH0yRZu+M49hnSF9NSx4HuwVzb8xpxNytpj1XqeZx7zk5l9zoHavcK9XlyduVTP/Bo5K+O721j93W6uZHNlR6dl2iLSm0r3mMTCiNuM0LDGCW+x/ZVDFf8npcb4HGycicnhS4CSHlZvG9eCkPrFU2J1c9eYSPl/uzjx9sXw36QXlxIf5c96wTgCMqx4b9euWbJj4GCQMNl3w3j7bdF2rKDIvdrnqZ5y6joEwcw4G/wl8bTzxwyY+XprG47O3U9FplNn388Purn/lhWZyXoBLPzSvL9oDK99v/k25HHDOi3DiXdB9nNm2v6566782k/6u/hhWfbSfTw3YUx04DboYQmL3f/yBOn+6e/1QuwAVZcLCF6HSA9+IV5a2/zVFWltJjnvcZ3TP2sCpW2wwUaGm8E5mYbmnWicicthS4ORJPj4wYoRZfPSjaAkfHwuvXjGcSdUT5077bDXPzt5Mpd3JK/NMF7S/nNijtrhETVGJP3bsJdMZClO+g6SxUFlkuq7VdMPL3my+ofUNMJPl+ljh0o/hghkw9m/M3ZRVm81yuuD7DlPB6g8RieCsHse07WeTtYjqYQK0428z2+c/1XwQYPWDQRfByfdC4nEwdhqMuKbp4ytLTGbnw4vhq7/Ab0/v/4OryTh1Omb/xx6MjkNN4QxwB48H64trzcD2mdMOtVUtM+Eh93prZ/pEPKHm7z2mNwWuIPJLzZwMiZFBxIcFAJBZUOap1omIHLZ0t+5JgYGwdKlZAgM93ZrDRoCflecvGcrUk3oA8MIv2zjnpd/ZlVdGTIiNS0d2qT22V1wIAzuFUWl3csuHK6jyC4XLP4fx/4ABF0BYB3NgTaGHzseCr82sdxgMgy9ma3YJd36+GjAV/wDe3h5sJqk98ykT+BTscpcv73e2KSIx/GqI6GK++V30SsveXFxfOOV+6H9u08esfB/KciGweizY3m3NZ3lcLnfGqXSvCbrS1zR+rNOx/5LtTel+knms6fp2sGpu+lY3UwGxNcX0MsEyHN7VDHctN2PqNAeY1EyV0Gk4qdXjm2JC/An292W87zpW+N/AkJ8v9WADRUQOTwqc5LDk42Phzol9eeLCQfj6WNiUYbrc3XBidwJt7lLmFouFFy89hhB/X5Ym5/HUj5vBLwDG3w2T33Kf0Ld6bpPeE2s3bUwvZMpbSzj1P/PJKa6kb0IoH14/Ch8LrErLJ9Vep4jFnH+6xzf1O8d9zlMeNOsLnms6uFn2Jsx7ArI27v+NO6pg4Utm/eT7IG6AWU9d1PRrCvdAcSZYrGZs17I3TTe/xvz6JLx4DPz27P7bUmPLbPj4cvdcWtt/afrmfd2XZmnObXWCusL0lrfjUER2Ax+/+pMqH27eONmMNds629MtEU+rEzilVJci71o9qXhQSChRlmJsZVmw41d46ywzXYOIiOyXAic5rF1ybBfevmYkoQG+dI0O4vJRXRsc0y0mmKcnDwbg9fk7eP+PRsYP9ToVrvoGjrsZgCqHk2veWsq8zdlYLDChXzwzrhpB58ggxvSIAeB/a/a4X++oMIFJ4ijoWKc73IALTDajstgUimjMyg9g3mPuuZy2/gy//6fx8tjrvoSCVAiOhaGXQ9fRZntKM4FTTbYprj/0OcOs75jb8DiH3V0Vb+5jkLWp4TGNSV1ogkarnymaUZwJmesbP9ZeDl/fBAW7mz5fcIwp/w6m+2NbykuGz6+FyK5wX6bJEh6O6pXnX+u5doh3GD4FRt0ESSfUjm/qWp0tDwg3WfbAylzTtTjl99adk05E5AimwMmTSkshKckspRqUfrBO6BXDsvsmMOvWsQT7+zZ6zOkDO/CXcd0BuO/rdTz5wyaczjo3m4GR0H28GdsEzNmYRUZhOTEhNub+bTxvXD2CxOobj3OGdATg21V1AqfJb8P92XDt7Prj1Xx84NR/mvW6lfpq7Flpqu8BxPYzj4tegp8fgrQl9Y91uUzmCmDUjeAXCF2qA6fUhU18OphxUxe9CWPvMO8RzLn3LbO+/Rcoqc6KWSyQvqrpc9ZV0+2v8wjTTbG5bobL3zbB05YfGt+/ZxUUZUDPU83zts6eZG2CdZ+bYNXHuv/j28P6r8zn1JjVH9cvSFLDYoHh1ePi7Br0f9Trdzac8W+I60dyjsk4danOOIVEm8DJ31kGZXnm+LxkdfEUEWkBBU6e5HJBSopZ9J/WIfH3tTYZNNX4++l9uW2CmRT3lXnbufmDFRRUD5re14dLUgG4aHgiSTHB9fZNHJiAzerD5swiliXnunc0dePdbSxc8r67MIPLZcaiFOyCT68CZxX0PgNiTal1IquzZvkppuR5bvW4m62zIWuDmevp2GvNtq7Vcw9lrDVV/Za+0XAupZBYE7QNvACiuptxV84qc4NeV82Yov7nmXmxhvyp8fdTl8vlnoA4YTBc+AZc/C4kDHQfs/kHd/e93qebbU0FTl/dCM/0AUv1P0075pnuiW2lZkxTVDfz6HS03bVaoqocPpsC//srZG+pv89RZYqB/P5s4+PIIpPMY1tMniyHreSc6op61f+ORUdGuXd+eb15rCrVhLgiIi2gwEmOGhaLhdsm9Oapiwbj62Phh/UZnPnCbyzcnoOrTuCallvKb1uzAbh0ZGKD84QH+nH2EPOt7S0friSrqAXf8Peb5F5f9l8zFuX5oZCfam54z59usgYAEdWB04Zv4LnB8MJQk4lZ8ILZPnyKuzBEWEdzvMtpskhR3eG7O2Djd019CKb7IJiqgjUT9Jblw6ZZZv2E291B3P4UZ5ry7hYf0xVwX/YKmDUN3jsf1n5ep6vgrw0rDZbmQnb1OK8Rf4agaKgodGfk2kJNUBoYYX4ej3WqH6i5XLDmU8jc0HZtqMtZ59qZ6+rvqzsGbt8CHnnJgKvOuhy1Vn9sugVXd/VN3mv+zpKiTeAUFx7gPjbxOAiv/jfucC6MIiLSThQ4yVFn8ohEPr9pDF2jg9idX8ZlMxZz6n/m88KcrSTnlPDRklRcLhjbK4au0cGNnuPhcwbQIzaYjMJybn5/BZV2Z8sbEDcAQjuYm2TfALj4PXPjXqMmc5C9CcrzTUDSYQic84IJKEZPrX++XqeaLnhWP0hdDLhMxqI42wQGn1wBi152H3/yfTDsChNszfybGTe18X9mnFZsP3dZcUeVed2su5p+LzXd9GJ6g810BcLphGVvmYIRy9+GgjTzfvudDbF9TaDnqIDt+4yzqilwEdPHZMkuehNuW2e6ANblcpngcOd887yiuGG3xpbK3WEeOw4z1Q/tZaa9NdZ9Yb6Vf3Ni469vbf6hJjAGdyavRs2Af4DMfcYx/faM6d4JCpyOdsvfgZ8egF1LKamwk1VkJuCuyZzHhQbwbNVFbHB2peqCN9z/3uQqcBIR2Z/m+zaJHKGGJkYw89axPDpzA1+s2M22rGKe/WkLz/60BV8fk/m5rE5Z832FBvgx46oRnPvSApal5HHhqwu59ZRedIsJYu6mbArKqrjiuK4k1P12t0bX0fCX32DRi9DjZFP2vK6E6ud+QXDSP+DY602mKLoHnP2fhuc76xn3epfjTBCUtR4+usQETwWppjpdTcBl9YNzXoKIJJj/JCSdAIFR1cGc3Z35ylwPP/7DrA+8ELqManjtjOpsUMIg97aidPjhHhOE1IxROnGaGZMFJuu0eDps+R76nmWCvIAwKNnr/nzAPR5rXxu+MVm7VR/Aravg21tMEHXDPIgf0PhrmlLbVa+7uYHM3mRuIKPMeDhWVXdfrCg0GbGgqEZP06pqAtd9M201RT7A/G7UlbPNvV6SZbJ5tsaDfjmCOezusYmdhtdmm6KCbYQH+gEQHWzjZdeFvFB5AYt8YugQ1Q2Sf1PALSLSAgqc5KgV4u/L4xcM5p4z+/Hjugy+Xb2HBdtysDtdxIf5M6F/fLOv7x4bwouXDeOm91ewdncB17+7rN7+D5ek8twlQ2sn4a1/8Vg49ZHGTxzT0wRWIXEQmnBgb8rXHy54DV4/yZ2hCIo2hSHqslhg3J0w+GJzHYBeE+of03GoyUytfB8+/7Npc0URHHcTjLjWnKPmZiuhTvAX3skEfD/db6p2RXSBYVe59/c+vTpwmm2yR8deC2+daSoPAnQZU78dZXkmo3Ly/WYM0uz7zPbj/2q6LDrt5jq/PAqXHsDcT06HezxQZDezZG9yB1MVxZBSXXTjujntEzSt/dzdDS99jfl8agJZe6UpmT75rfpdP8HM5QVmLq2+Z7V9O8U7ZW8045VsoRDdi+R1mQAkRbsDbR8fC3Gh/qQXlJNRUE6HyOrxfeqqJyKyXwqc5KgXFuDH5BGJTB6RSHZRBb9uyWZQp3D8rPvvyTq+Txy/3X0Sb/y2k/cWJVPlcDGqexTZRRVsyiji6reWcMPY7tx+am8C/A6gatu+WagDkTAIznnRBDyDLjJFHmqyPfuqKUTRlFMegg3/g8JdZgHTvS99DZz5NEx8DJIXmExXXcfdbKrVpa82kw3XTCoM0PV48A8zmZE9K01mpMMQSFkAVpvJgNVwueD9i2D3MjMuqiDNBFLhiXD8bWZOrjOegldGweaZZvLcmiIc+1O423SX9PGD8M7uAhE1XZY2zzJZs6ju7vLobW3e4+4gqDTHzI0V3sk8v+A183PdV3mBuxrixe+a7J0cnWrmZ+tyHPj4uMc37VPgpntsMOkF5azZVcCwpBPghDvMVAoiItIsBU6eZLFA//7udfG42FB/Lhre+YBeExPiz9/P6Msdp/bG6XIR4GelvMrBw//bwEdLUnlt/g5mb8jkwUn9OaFnDL51AjKH08WstenM3ZzF+t2F7C2p5Jrjk7hpXA98fA7hd2LopWY5VCGxcPU3Zp6oiC4mI/PLvyCnuuJbQDj8+UcI3Sc7Z/WFK782VQDrBkJggqiz/2MyPB2HmZLtU2aauWR8rO5AAczfxUn/gA8uco/5CYqB815xj6mK7Q2DLoY1H5vA4/LPWv7+hlxqslU+VtMecAdOaz83jwMvMu0ozjLX9mmjoaH2CveYq8AoKMs177nu5+FrM8FkYTrgMsVBajJUIfEKmo52m2aax+qs487qUuTd9hmrObZXLAu27eXXLdlcPWYkJI5s12aKiByuFDh5UlAQrG9iolA57Nh83TfUAX5WHr9gECf1ieX+b9axM6eEKW8tJTzQj7G9YugVF0pksB/v/5HClsz68yk99eNmluzM5d8XDqJDeBOZovbUcZhZwBR46DjMdM2rySLtGzTVCIpqGDTVGHRR/ecWS9M3bz1PMeXcdy+HnhPMN+P7ln4fdxes/cyMqUpZ5B4n1ZyILqaaYY2oOl2WSnNh+xx3W/97GqQtNmXaY/uZincdh+7/GgciZ6sp2BEQDqf9ywR0NWPHijJMls4WBHMeNhMkH3cznF4nQxXd08xLtWMuhHWC/ue0bvvEuxXsrh4HZ6kNnGrmcNo343Rir1j+/f0mFm3fS4Xdgb+vl8xhJiLi5RQ4ibSh0wYkMKp7NM/O3sw3q/eQX1rFd2vSgfTaY8ICfLn8uK4M7xJJZlE5//xuA79uyWb047/QPSaYE3vHcsvJPYkJ8ffcG6mr5yntf82+ZzU/die6h8mwrXzfZKfO/o8Zv3Ugasd6JJtgJCgGgmNNafaACLNv288w9zFTAOOGeWabw24ycPGNlGM/ENmbzGNsPxh2ef19P/4D1n8NZz0N0WYuMjKqK+vVBk49THfHH/5uxpEpcDowVWUm+Ijp6emWHJzN1dMJJI6qHbdY01Wv2z6BU78OocSG+pNdVMGy5DyOdy435e4HXggRDadgAEym85uppmjLgAsAF2z+3lT1bKorsIjIEUaBk0gbCw/04+FzB/LApAGsTM1j8c5cUvaWkF5QzrDECK4d27224hXAiK5R/OOrtaxIzWNHTgk7ckr4auVu7pzYhzE9ognx9yUy2NboGKyCsiocThdRwbYG+454p/7TdLNLWWDmvWoucCrNNQUvJj7mDngiuphxW5HdzJimOzaYTA+Ym8WtP5qgyVFpAil7pRkD9cmVZqzWdXNMt8GDVRs4NTKH1u4V4HKYyn9BMWZbRnXxiJquetG96kyCm1z/9RlrTSZuxJ9NN8rWkJcCS16HMf934EVMDoTDbsbX1by3tvLt/5ms5Z8+gr5ntu212kL8QBj8p9rql0XlVeQUVwLQtU5xCDBz2p3YK5YvVuxi/pZsjt/1b5Otiu7RdOCU/JupZLn2c+g2zkxzsGsJnDe9dboFi4gcBhQ4eVJpKRx7rFlfutR03ZMjltXHwoikKEYkNV+drU9CKF/cNIaC0ioW79zL83O2sn5PIfd97Z4Q1ccCHcID6R4bzHHdo+nfMYxvV+3huzV7qHK4SIoO4rju0Vw3tjs940IAKK9yANQWqaiZs+r4njGNV/473ARFwdX/M3NHDbvCvX3lBybA6XiMufl2ueC9c00w8eX1poKhj4/pejjy+vrnrBlfVFMa3VEJWODcl9xdFR2Vplz5R5fAhf9teXGKfdVMcBvXz7Rx6RumtPSom9wVzzoOA79gU9CivADyU+D818w4MP9QU/UQTFBTU5EvPxXePtvMCea0w+ibG167ohj8QxpuL9gN67+CEdc0LG8+82+w7SdTsOPidxt/T9t/MfOARfc03S0PJmibfR8sftV8tvt28WwtZXkmowfw6xOmZP7hNu606+h6XVSTc0oBiAmxERrg1+DwcX1M4PTrlmzu6dzNBE7NzeU0/ynzOPxq0z2390QTOC17U4GTiBw1FDh5kssFGza410XqCA/y47QBCZzcN453FqXw7qJkcksqKamw43TB7vwydueX8dvWnAavTd5bSvLeUj5bvosLj+lEYZmdeVuycDhdHNc9mqhgG9+tScfhdDHjtx08fsEgLjm26XmrDsaO7GKWp+Rx3rBOLapQ2Cp8rKa8eY2SHJg1zZRo3ldwHFz0VsuKPcT1g/AuZk6sM59ylwP3tZkJjGecZAo7zDgJ+p9rvv13OU3AtW/FwaZkbzaPsX3MTfsfr5hz1swlFdXDlF+vaU/GGkj+HYZebjIFYDJhFh8TKBZnmYmVP73aBE1gyrofc6UJssD8u/PVjSY4On86DLzA3R6nEz653GTT8lPhzCfrtHWLCZoANnxr5pGq28WtqtyUo1/yuru9jsqDC5xqCmb87zbTlawtAppNM02FRTDB6s5fm55HbF+OKpPh7DjUzJHmCflpDTJFO2sq6jUxiffYnjFYLLApo4jiPomEQNMlyVMXm7nSfPxgzK1m27ArTTGWXUvMlxB153ITETlCtdPdjIgcLF+rD9ee0I1f7zyJtQ9NZPtjZ7Lk3lP44qYxPHLuAE7tH0+niEDOGdKRb285ntUPnMZbU45lQr94HE4Xny7bxQ/rMyivclLlcPHb1hy+WbUHh9NFj9hgnC64+4u1PP/zVqoczoNqY6XdyZyNmeQUVwCwMjWPc19awJ2fr+HRmRtb8+M4MPZyGH0L9DjFzGdVI7QjXP0txPbG6XQxc0167UD6RlkscNXXJqO1b1YqJNZUFhxyKWAxE/TOfdTcVK770n3c9l9g13ITrOxeAb89C+9dAK+NM2OzgmNMAYjYfub4mhLoLifE9Ycz6gQuNZPkfjMVfn7Q/cWLr80UhgDTXS/1DxNgBURARFdT4vyPOgUx/njVVCN0VMA3t5iAqMaaj03QBLD8LSjY5d63uM45cMGC59xPnQ74/Bp30NRvkgnKbI1k1LfPhQXPm/bvnA8fX24m763r/Olg9YfKIlOgoy2EJ0LvM0xlQoDfn2v8uD+mw4r3TFAJphLiB5PhvxPgldFm8ukdv7ZNGxvjdJpCIS8MM9euo6nCEDUig20M7hwBwHdpZqLussxtDQ90ueDXf5v1oZe6A7TQePcXCEv/e2jvwxvtWWl+N+2Vnm7JkWPLbFj1kadbIXJIlHESOcxYLBbiQgOICw1geNdIrhqd1OCYk/rGcVLfOBbv2MsnS9PoGBHI6QMTCLRZmbspi9TcUs4d2oljukTw1I+beWXedv7z8xa+WLGLv57Si9MHJhDsX/+fB5fLRXmVk0Bb/QpcJRV2/vLecn7flkOgn5XJIzrz1YrdFFXYAXh7YTJjekRz2oA2HAfTlPDOcPK97uf2SijJNoPnq7MDr/66nad+3EywzcpLlx3DSX3jGj9XdA93ZqfBdTqZG/zRt5ggyF4GWNwBTvIC+PASM4jeP9xkrupa9RFc8339bac8YMYtdR9nBvzXzbQcd7MJjHYtNdkSq7/7fUYmme5zeckw5BJT6r2yxHRH++JaWPiCycqV5ZmsEJhgq3A3fHoVXD/HdMsryTHzalltZnLi+U/BpOfN+LDV1Tc/J99vbi5rgjWXyxSn2DzLtOmS90yXrhole81nYAsyQeSHl5igLTIJfnrAtHnpf+H4W92vCYoy72PFu7D4tZZn8A5E93FmyUsxQciOue4sUo2CXfDzQ+ZnGxJngvEvrjXHAuzdasb9WP3hr6tMqXh7hekGGRzd8JqNqSqH4kwz3q65zJrDDpu+Mz/Lmomut/5Ub2LkmsBp38IQdY3vHcvqtHy+2unHn/whL20jvnY7fr7Vf/v2SjP2a/svYLGaudPqGvFnk61c8ymceGf90vmHM4cd3jvf/I3YK81k4U2pLAG/oIY/r73bTTXOvmfBOS+0bXsPB6s+gq9vNOvRPSHx2Ja/9od/mC8Grvq66X+DRdqJxeU6uvqIFRYWEh4eTkFBAWFhHp7zpKQEQqrHFRQXQ3DT/8GJtKVPl6bx5I+bageT+/pYGJIYQUyIjQq7k73FlezMKaG4ws7o7tH8ZVx3hnWJJKuwnGmfr2F1Wj4WS/0ep6O6RdEnIZR3F6UQHujHzFtPoHOkd43jS9lbwmn/mU+F3WQQfCzwp5FdqLQ7Kat08LfTetM9tpGxPweqotjciO1aYp77BUOPk0y59soSc3MV1+/Az1tVDlnrTUGLoOqxc19PhVXvw0n3mjLtNZxOeG2sKbt+2r9MsLLiPUhdBKc8aPYVZ0JYZ7hmptmfu9MEM++dBz6+cMsy8A2Auf8ypc+v+9m0v2Z81Lvnwo55gAUmvwUDzndff9vP8NVN5rxn/wfev8Bcr9dpZvzT2s9MBi0oBm5bA1t+MDfsx001Y7NeG2vaMHWJ++apKAPePN2UZe9zxoF/fo35eqp5HHdn/YIUX1xn2thltAlya8rCW22my+fuZbDoFVMo48I3TBbr0yvNZzHlO/BtoipmVZlZNv7PFB8pzoCYPjB4shljNub/3O/X6TQTS//yT9N9Eszv0hlPmHF9dW7ez39lAStT83n5smM4a3CHRi9dUFbFf3/fSX72bu7ffCF+FgcFHccSftlbJpNa87tksZpxfUMvq38Cl8t0T92zEjofC1NmmS8k9qyAiKSWB4yekrkeQju4/3ZqVBTBfwaYcYR+wTBts7t7a43SXJjziBlTOfACMwavbvD01Y3uLxj+/GPbBPyHi/Vfmyy0qzpTO/QKOO/l+seU5Jhqpft2+SzcA/8ZaIrj9D4dLvukXZosR5cDiQ0UOHmSAifxIqWVdt5emMyHi1PZlVd2QK+NDPLjrWtGklNUwfRftxMb6s8zFw/B18eHya8tYnVaPuGBfvzfyT25cnRX/H2t5BRX8N3qPczekImPxUJcqD9xYQHEh/nTMSKQMT2iGx3U3lpcLhdXvbmE37bmcHzPaDpFBPLpsl31jukcGciXN48hLjTg0C9YXmCyKTG9TLaisa5rreGP6Sbrc8n7Zt6tunbMg9WfwPmvNnxdykKTAcICd+2oPx7pvfNNEHP+6yb7A6ZL3r7zaT3T19z8nPYojLml/r7UxfDhZPM5YAFcpgvitbPNTamjCl4aYQK1qB6mW2F5gcm8jf2bCZBSF5lzPZBrrp21EV45zoy9+dMH9bNbdblcZuLmjsPM55+XbLJLPlYzhuy4m6DPmeZnUlNUo66dv8E7Z5t23zDPBDIvDDM3zxe/6/6cK0vAN9CMm8vdAa+PN++h79nmxtovwGyvKndXc9w0Ez7eJyCpa+JjMHqqCZq+udl9Mx4UbTI+x17XoKphRkE5Jz45l0qHk59uP5Fe8aGNnLi+d6b/m4vTn8Hm48B67U/Qebj5fN+/0GQae53a+Atzd8Lr48z7nPQ8DJoMzw02+y560wSai16CdV/ACbe3XYGPlrBXuou6ALwyxozruuT9htMsOOzVv4874eT7TEatxqZZ5mdRlufeduo/3ZnS/FTz++E0WXc6jzS/54dbwZEDUVFsMtX7vseKIph+gvmbSxprqjP6BcHfNpk568B8AfL6ePNvx6DJcPoT7qB77uPurqIA1/zQsnn6RA6AAqdmKHAS2b+03FIW78ylrMqBv68P4YF+dI8Jxt/XyjuLkvloSSqllQ6CbVZ6xYfy1EWDm7w5S8st5fp3l7Epo6h2m5/Vgt3parYmir+vDxP6x5MYGURJhZ2oYBtXHNeV2NDWmc/qk6Wp3P3FWvx9ffjxthPpGh3Elyt2syotn4TwAD5blkby3lIGdQrnk78cR5DtMOnZbK+AbXOg6xhTHGJfTmfTBTEqS8xEvPtO7rtnJfx3YsOud/ta9ZHpotbtxMZvErM2mnFdRXsgMApumFs/q1O3Ow+YG6tbV5mMwPqv4bOrTfGLa7433+BXlphM0OZZJvNz0j8gqrt73q1Ow002LHeHuZFtzq2r3JMg1yjYBbPuNN3gnFVwzFVwzotmX2muqabYXJn07b/Ah38y3RG7nWgmjl78mik8ccXn5pgFz5tuioGRcOJdpoz+xv+ZjFtEV/O88whzvReHmyIbY+8w3TWbmD/poW/X8/bCZEYmRfHpjS27yfx0WRozvpjFmdGZ3D7tAfcOe0XT2bIaW3405fTH3Gp+7l/dBKs/ND+r8ERT/bHGea82zFy1h/xU88XAmFvNWC2nA54fYrq1+gbCFV9A0vH1X7PmM/jyOvN7+Nc15u8pe7MZl2gvg7gBJnO86CWTlbv6f+Ycs+6CJa+ZQD17swmgbpgH8QPc585LMb/X+2ayDkfJC+DtM03X5EkvNPz3o6oMNn5nMnOvjjG/K2c9Y4J+e6X5UqLu+MXgWJj8tumi/NwgE1AljTW/N4P/VP/fr6oyE3jt+7crcgAUODXDqwKn0lLoX/2t44YNKkcuh41KuxOH09VgvFNTHE4Xny9P45nZW8gqqqjdPqRzOOcO7UREkB+ZhRVkFpaTXVTBxvRCdjRSrCHQz8pVo7vSMSKQ8ioH5VVOyu0O/Hws9E4IpXd8KCH+vvj6WIgIsmHzbTxAeGdhMg/9bz0uF9w5sQ9TT2o46WlyTgkXvLqQ3JJKAv2sxIf5MzQxgofPHVhv3q2jRlm+uYE+1MlO89Ng6QzzzfK+3XJcLvONdFWZ+VY6prcpQlBj609m/E/dua4cVfDZFDPmZ183LTKZndydsPBFc+7CPaZrY1SSuV5FEXQbWz+jAKYb1+vjq0vQY4pHnD+98WC0OTvnw0eXmnFiNXpOgEs/dlfhK8szXcLqZkP2lZdsAqrBl9ROcNuYrKJyxj4xlwq7k/evHcUJvWJa1MyMgnKOe3wOFgssv+/UQ5sLrqoMvrvDBE9gboS7joG0JabbWmRXMwZo1p3mhje6pwks4/qbwKu8wPyeJAx0n3PWXSZb2P88042whstlunz6BUFAE/+nb/kRvrzBVJcM7wK3LDXZP3ulqRy5dTbYQkxmLz/NXGf4FBMw1dzo9zoNTv+3CQR/vMf8Tl32qclafvUXWPMJjLvbBLTP9DWB1ZVfm9+vDkPMewbz+zr3UVOAJDjWdOvsPq75LzS8Ucled1bIUQX/rP49s1hN99KT72u8yuQfr5qM+IhrTZfh7243hWj8w2HSc/Drk5C9EcbfY34fPr3SdN+9Y4M7gC8vMFVD96wyXzoU7THZzJMfOLw+w8ay9keqwnQIa7zLsDdQ4NQMrwqcRI4ydoeTvNIq7E4nvj4+TWaPXC4X63YX8v26dMqqHIT4+zJ/SzardxW0+FoBfj4c0yWSYV0iiA72JyTAl9ySStbtLuC7NekAXDaqC/88dyBWn8a70CxPyeP6d5eRW+KurDWsSwTv/nkkLuCrFbvpFRfCmJ4tuzltib3FFVQ6nHQIP7AAxeVyYXe62q/0uzexV8KiFyF9tfn2uaY74CXv1y+TfiDKC8034WV5prtc37MPvqvV7uWmYmBgJJz6SNPd3lrBY7M28vr8HQzrEsGXN43BcgBtnvif+WzOLOKFS4dxzpCOh9YQl8uMCdu7HY670WQBS3LcQU/GOpi+T4Ynoqu5Oc7ZYipf3rHBfOYVxfB4deEJixUSR5psVkWRCSgrCs0E1J1HmGO2/mxeV7jbBK5rPzPbOx5jsqbhnd3XrCqDDy82x9V1/VwzJ9uW2WY/LlMM5cRpZn/dbn+VJfD+RabbZkgspC2FDV+bwKDu51+WB08k1b+OxccEVv3PgxNuM9vyU82E1VHdTbXNyhIzpUJQtCnE4uvvPm/mBjMxcVC0GScZ28eML6sJIPbtelpZar78qNnmdJrPe9dSs4y51f03U5xlHusG6kWZ5ouPRa/An3+ADoPdbf7pQVhfXUk0aazJGI34c/2iIeUF5vcguof5cuLVMYDFjF3qPdF0Y930nenS+f5FZtqDE26HCQ+5z7HwJZhdp+hPjZAEuHWl6XJbnA3f3mImNQ+KMkGWf6gJ0i0W87nXBGL5qaa7b0tu7F0ukwErSjfvIyDcZJIPpOt1eSEs+y8se8v8ntUEoDnbTMa+5lzF2SYg3/it+Rmc8qAJ6td/ZQrVRHYz2evu400bmvqZl+WZMakWH9MFO6ZP4/P27Stnq8nmF2eZL87i+sGwy93TYoDp0pqfYjL+4Z3d1y3JMb+7YP5On+1vAuFxd5qu6gW7TGGdY65q+efWhhQ4NUOBk8jhyeVy8dOGTL5ZtQcwXfn8/awE+PlQVulgU0YR27OLqbA7sTucOPfzL9udE/tw8/ge+72xrLA7SM8vZ3t2MXd8upqCsip6x4eQUVBOYbkdiwUeOXcgVx7X9ZDf43dr9nD352uosDu5/dTe/OXE7uzKK+OrlbtJ3ltCZmE5HcMDufesfkSHuIPOP3bs5eH/bSB1bwm3TejNNccn4Xs0BlCt7SCyAJV2J6/M20ZmYQUPTupfO+F0e2QUluzM5eo3l1BW5eCtKcc2XSGyCY/O3MCM33Zy0fDOPD15SBu1slp5gSndn7vDBFHJv5npA2pEdjM35qEJ5tjFr5nuizVVBOvyDYS/p7hvhF89HjLX1T9m5A0mkGms22FVmRnrtmsppK8xY2jOesa9P32NyVhOeq7hRNA1Ghsbt6+a8ToBEeaGfuc8U4UTTKB421pzY/vNVPf2xgy51GQ/wZS/f/ec+vt9A03Z+IoiE3Tek+Zu28ujTDAbHGsCivxUE3jWmPSCmeQY4OfqAijxA83NvdNhxkK6zGTqjP2bGYNY14Zv4Oub3RnWkATzvhrLprpcpvDMoMn1Jy2vUZprgsJ+57gzdgAzp5kJwv0CTbfVoBgzX5/TbiYMP+PfJsu7eZbJZFWVuMebYTGfxZ8+dBeUmfNP+O1pk+GO7WOChPICk8X0DzUB+fi/m2O3zTGFbeqyWM3rQuJMAFu3UMgbp0LudlOEJDTBfN45W4Hq/6BOedC8B4DpY80XAR2qu5Dmp7oLamAxxXlieprXvzyyzj5M1+e4/uZ1xZlwzy6T8cvcYL6gqHus1d90MY3uaa530Vvun8+vT5lz5O4wf5P7Ou1fJqMIZo7AzbPcWXlbqAmSK0vMOf70oSl8tG2O6SZbM1de/CDI2WwylTcvOrjCSK3sQGKDw6TTvogc7SwWC6cNSGhRWXOXy8W2rGL+2LGXjRlFFJRVUVxuxkl1jAhgTI8Yjm9hlsjf10pSTDBJMcG8f+0oLnvjD7ZkmpuCmBB/cooruP/rdezKK+Wq0Ul0ijjwrmyF5VU8O3sLby9Mrt321I+bef+PFNILyhscvzItn3euGcnekgre+G0nM9em1+57dNZGvly5m+cuGUqfhCNg/IQnHWCgk5Zbyi0frqjNjA5NDHdPLN2GQVNxhZ1HZ27goyVpABzTJYLxfWL386qGTuwdy4zfdvLb1mxcLleLslUb0wtZu6sAq4+F0ABfTu4b17KgPSC8/rfNlSVmQmcwY9OCY+ofO+4us+RsMxUMrTYTxER0MZmZmoDI5TI3wPYKcyObOMp0jdx3/FJdfoGmRH/dybPr6jAYLpzR/PtpSWav/zmmnYMvNt/OD55s2pax1nQNtPqa9gdEQJcx5sa5LNd0I/QLMN/iV5WaKRVqJAyCkX8xx2VtMtkje5l5rFFZ7B5LVZJtbmCL9pgFTDfRTseYAKFDnYC5IA1wQeba+u+j80gY9RczIXWD93iumUbh40vNTfmY/2u6C6rFAld90/TnFRTlvkmv66ynTVc+X5v7fUV0gdn3mc/J5TITlWdvNkELmMDUXmayLy6X2VcTOPkFABbzmdX93GrUBIpgbvItVjPnW0isycAVZ0DWBrOA6dJZk6WrLIbSvWapG8xH9zKB56DJ5nlprulKWlFYP2DpNNw9rqsmExjTy3QT3bvNBM7Jv5uff0r1309sX3c3ydg+5jPyDzNVSStLoCTLfAlRIz/Vfe7NM93z91l8THYoto/5Hdw+p36AW1lsgibfQPM7VVlkurXWWPOJCZx6ngK3r4MFL5hMW83vU9LY+gHdYUIZJ08qK4MTTzTr8+dD4CGOHRCRNrdudwFv/LaDCf3jOWNgB178ZSvP/by1dn/X6CBGd49mdI9oesaFEOBnJSrIRmQjY0b25JfxzqJkPvwjtXbeq5vG96BHbAgPf7ueogqT0RrfO5bRPaKJCLLx/M9b2Z1fhs3qQ2X1hMUWC1w2sgv9OoTx1I+bKSirIjzQj7evOZZhXSIbXFdaj8PpYvb6DL5bm86cjZmUVzlrS/MP6RzON7ec0OZtuOXDFbXdTy8dmcjfT+9HeNCBj8Mrr3Iw9JHZlFc5+f6vY+nXoen/I6scTl6Ys5WX526rl92ddlpvbjm51wFfW1rA5XJX8tu3hHoNp8MELAW7TMBZ072vJnCvKjcVK0uyzTilkDiTqbA28T16wW4T2FUUmsxc1zHmxn1/KopMINd5hOeqCZbmws5fTZGOiK6mHSU5JvsUEt+wO1vyAjMGMijKBBr2MpOxC4lzd691uUympCYYdLlMl9CsTSY4KsszgXHNzyc/1XwWhXtM977QjiYQb2ycotMJqQtN4ZDIJNOdMXT/XxTiqDKTquclu79IqDs2tCzfPTbT5TJFejbPMp9PZJIp2lHzRcX6r8x+X38YdLF7wuvGZG00WbnwRPOZ5m43XaX9Q013vqjuDX/2helm7GOnEWZsn5dQV71meFXgpKp6IkeEr1fu5q2Fyazdld9oF0GLBY7vEcOFwzsR6u9HTnEFP23IZO7mrNrje8WFcM+ZfTm5r/kPb3d+GXM3ZTG+T2y9+a8yC8uZ8tZSNqYXYvP14ezBHbjuhO7072j+PcspruCGd5exIjWfIJuVh84ZwKBO4cSHBWB3OnG5IC7U/4DGvtRVUFrFtuxi8ksrcbnghF4x7u5oraSs0sFtn6xkT345p/aP56zBHejRGvNptTK7w8nUD1fw4/rM2m0jukby4KQBXPDqAqocLv53ywkM6hzeZm1YlZbPeS8vwGKBd/88krG9DjzTVNd17yzj542ZXHBMJ569eGijx2QXVXD9u8tYlZYPwMikKJwuF8tS8ogI8uP3u08mxF8dWkTk8KDAqRkKnESkrRSVV7E0OZdF2/fyx45cMgvLKa9yUFhub/I1x3WP4roTunNy3zh8mihSsa+SCju/bc1mZLfoRquflVTYueG9ZSzYtrfR1/eIDebSkV0Y2ysWH4u5Ef5lUxaLduwlNMC3tjphVlEFhWVVxIT6ExNsY0VqPn/s2Iu9TnTYJz6Uly4b1qK5glqiyuHkxveWM2dTVr3tl45M5N6z+nvNDbnL5eIfX63loyVp2Hx9mDImibMGdWBw53AsFgu3frSSb1fv4dKRiTx+weA2a8OfXv+DxTtzufCYzjxz8aGPS1qdls+51YHYrFsbZp3ySiq5dMYfbMooIjTAl8fOH8SkIR1xOF2c+uyv7Mgp4e9n9OXGcT0OuS0iIu1BgVMzFDiJSHtLyy3ls+W7+HlDJr5WC1HBNvokhHLJiES6t1EmpbzKwX9+2sIfO3NJ2VtCfmlVba+JQ/1Xv2N4ANEh/uzOLyO3pJIAPx9O6BlLXmklBWVVlFU6qHQ4CfDzIdjmy6BO4Vw3tjt9EkIpqbCzfk8hmYXl5JZUsre4gpySSsqrHHSKCGRrZjE/rM/A39eHv07oxZKduczbbMZ0dI4M5O9n9GVCv/hWz3KtSM1jU3oRp/SLIz6s+QmPd+eX8fLcbXy4OBUfC7xy+TGcPrB+Ra7FO/Zyyet/EGSz8t61I9mZU0rfhFAGdjr07FNBaRUVdgdLk/OY+uEKbL4+zJs2no4HMb6uMVM/WMHMtemc1CeWt64ZWbu9qLyKy99YzJpdBcSF+vPJX0bTLcb9/9bny3cx7bPVxITY+O2uk1s8XYGIiCcpcGqGAicRORo5nC58LFBS6eCbVbv5ZGkau/LKcLlcBPpZGd0jhvF9YqmwO9maWUR5lYO4sADCAnzJLq4kq7CcbjHBTByQQFL1zXJ2UQV3fLqK37bmtKgN3WODSdlbimM/JQ+tPhZev3I4p/Qz3RYXbs/hzs/WsDu/DIDQAF/G9DDZtqhgG/06hDGkcwTF1UFZfmkl0SE2YkL8a5foYFuDjF5BWRXr9xQwY/4O5lYHZ35WC+cN7cSZgzowqHM40cE2KuxO9uSX8fu2HOZszOK3rdm1XSwfO38Ql43q0uA9uFwuTv3PfLZluedvsljg+rHd+dtpvbFgIbOwnNhQ/2aDQJfLRUFZFam5paxKy+e71eksTcmtF/zeOK4Hfz+jb7Of6YHYmVPChGd/xeF08dJlwzhzYAeWpeRx1+erSd5bSmSQH5/+ZXSDLGOVw8lJT89jV14Z95/dn2tP0KSkIuL9FDg1Q4GTiEjrcTpd/LA+g9ySSmJCbIQH2gi0WbFZfSi3O8gvreSzZbv4YX1G7c1+h/AAEqOCiAkxgU90sD82Xx9255eRUVDORcM7c+ag+hmcovIqpv+6nS9X7G600uD+BNms9I4PJT7Mn8zCCnbnl5FdZzJmq4+FXnEhbMooqvc6q4+l0UBvdPdo/nxCN07tH99gX40vV+zijk9XExbgS1JMMGuqq+2FB/pRXGHH4XRh9bHQIzaYQD8rmYUVVNgdDO8ayTFdI9meVcKCbTlkFDZ8vz4WcLqgW0wwX089vtUnZb73q7V8sDgVgJgQG3tLzJi2+DB//nv1sU1mzj5cnMo/vlqLzerDExcN4vxh7jmTXC4XG9ILCfH3pWu09/x/53K52JVXxtasInZklxAb6s8p/eIPqFvojuxiMgrLSYoOJiEsoMXdbkXE8xQ4NUOBk4hI+0vOKWFrVjEDOoYdUpcyp9PF0uRcNqYXUlBmJ7OonDW78tmUXkSgn5V+HcNICAsgt6SS7KIKcooryK0uZNGYDuEBjO4Rzf+d3ItuMcGsSM3jw8WprEzNY0dOSe3r/KwWRnSNYmzvGE4fkNDiLpYlFXaCbFYsFgs/bcjk71+sYW/1hMq+PpZ648WaExfqT7eYYE7tH8+ZgzrQMSKwNot4sIU+mlNYXsW/vtvA9+syKKoeo3fJiET+cVa/ZoM0u8PJrR+vZNbaDACmjEniuO7ROF0uXp+/o7agxKhuUVw2qgtnDergkTnHXC4XK9Py+d/qPfyyKYuUvaX19vv7+nBCzxi6xQTTOTKQE3vHNvozX56Syytzt9cbkxfi78vEAQlMHtGZY7pEYvPVnGotZXc4Wb2rAIsFwgJ86RwZ1OrdckX2pcCpGV4XOCUlmfXkZAVOIiIHqcrhxGqxNPpNf5XDScreEjZlFLG3uJL4sAA6RgTQLSaY0ICmg4DiCjtF5VUE+/sSbPPF2gpZhMLyKrZmFtM5MpC4UH/SC8rZlFGI3eEiITwAp8uMj1qVlk+X6CDG9ozlmK4RBNk8UxSj0u5kaXIuEUF+DOjYsvFZTqeLp2Zv5tV52xvss/n61JuguntMMLed2pszBibg10gA5XC62LCnkEU7ckjZW0peaSUVVU66xQTTOz6U4UmRdI8JbnHwWFbp4NvVu3l3UQrr97gnfvWzWugRG0K3mGA2ZRSxM6ekwWtHJkVxxqAE+sSHUlrp4PX5O1iSnAuYbpiJkUHsyS9rEAwH2ax0jQ5m0pAOnDe0U+0XBw6ni1VpeRSV2xnTI+aICLAq7U4yCsrJKionv7QKm68PPhYLS3bu5eeNWWQVVRAX6k/HiEAm9IvjzMEdCKv+G1yRmse9X61jY7r75xIW4MsFx3RmQr94cksryS2u4IReMfSM0xx10noUODXDqwInERGRI9T3a9OZuTadtLwyCkorOX1gB649oRt2p5NPlqbx9sJk8kurABNcjEiKoldcCEE2KxV2J+t2F7B2d0FtxqspnSICOa57NEMSwxnQMYzEqCBiQ9wl93NLKlm7u4DftmTz2fJdFJSZa9p8fThrUAcmDkjghF4xtV3zXC4X6/cUsmRnLnvyy9icWcSCbTmNTjXgZ7Vw4TGdueHE7nSPDaHK4WR1Wj6fL9/FzDXptfOz1VWTPdyWVVybfYwN9efyUV2Y0C+evgmhHsnCHaydOSV8s2o3f+zYy8rUfCrsLZ/U1N/Xhy5RQVgssDWrGJcLQv19CQ/yI7+0iuJGPj+A8X1iuXRkF0Z1i8LX6sP/Vu/h183ZDOoczpWju9YGYyItocCpGQqcREREPK+ovIq3FiTzzsLk2gCiMaH+vozqHkX/juG1RT62ZxWzMb2Qlan5tRNB12Xz9amdJLpynxv5xKhArhjVlYtHJDY6MXVj0gvK+HLFblam5rE1q5jicjsXHNOJa0/oTkJ441UYnU4XReV28korWbxzL1+u2M3inbn131uAL/6+VnKK3ePtAv2s9O8YRu/4UJKiTVc1q4+FgrIqcksqsTucBNishPr7khAeSMfwAMIC/Qi0WQn0sxJks9aOM7RYzBi9vNJK9habKpb5ZVU4nC6cLhf+vlZCA3wJ8fclpPoxwM+cx89qaTST53K52JFTwu9bc5i5Np0l+7ynAD8f4kIDiAzyo9LhosLuoHdcKKf2j6dPQijZxRVs2FPI1yt3s7VO8RSAC4/pzD/O7Et0iD8Op4vftmbz0ZJUNmUUER8WgM3qw4LtOfW63vr7+tQL1sICfLlweGdGdI1iaJcIOoYHtEl31vaWVVjO7vwyeseHEuwl0zIcKRQ4NUOBk4iIiPdwOl1szizijx17ySgsp6zSgQXo1yGMgZ3Cm83AlFU6+GPnXlam5LF2dwGbMorILCxvkB3qHhPMoM7hnDu0I+N6x7VKt8uDUVhexbasYnZml9AhPIBju0XhcsH369L5auVulqfk7TfD1lI+FhOElVY5DmoKAquPhQBfHwJtVgL8rNh8fSirdFBYVkVJpaPedU7sHctp/RMY2S2SHrEhLQpUXC4XW7OK2VtcidPlIj7Mv0Vd8JJzSnhnUTLzt2SzPdt0qeweE8wZgxL4cX1mvUqWADEh/gzpHE6Qvy8VVQ4sFgjx9yMs0JfQAD/C9gkcQwN8CbL54nC6sDtd2B1OKh1O7A4Xdqd59PerH6TWrAf4WalyOCmrcpBfWkVmYTmZhRVkFpaTXVSBxQIBflYCfK0E+Png7+tT+1kF+pkgNizQrzag3p1fyvasEn7amMnSZFNN0/L/7d17UFTn3Qfw71nYXXa54wK7KCpGQuINE1SySTVpoALaVBM7NSnToO3E0aBja5KJOPGStjPk0qa2qcVJ28TOJJGUTDWpIzYEI3lj0EQU7/KqLwYTWFARWBZ22cvz/rFy0hV0ITGcXfh+Zs54OM+zu7+zP5+jP845z5EgX1aaHKtHcpwOY+P0SIwKgzZUBZVKwlVbD5o7HPAIgVi9BjF6NWL0asTqNfI9l9dzuT1o73bialcPnG4hx6EJUSFUJSFE1X8h7XJ7cOGKDXWWTnx5tQtOtwcuj0BUmBqjIjTyREEeD7yTAUVoEK4NhTZUhTB1CGL1GsXGY6+gK5y2bNmCl19+GRaLBenp6Xj11Vcxa9asG/YvKyvD+vXrceHCBaSmpuLFF1/EvHnzBvRZAVU4dXcDeXne9fJyQHdrnsFBREQ0UjndHjR32OH2CKhDVIjSqQPmwcn+eDwC/3e5E6earPhfixVfXu1Cj9sDp1sgWqfGqHAN1CGqaw/WdqKp3Y7Gtm7YHG509bjQ7XTD6e773zpJAmL13lksY/VqhKpUkCTA4fKg0+6S7+frdLj6vSTxepoQFWaMj8Xs1HgsmJ50y54hNliXOx1otfUgNcFbrHk8Ah+casb/nL2Eo9cmjRnoBCzBYFS45qZnZwdKp/664Os9m9l7CevNqEMk+SylXhOC9m6nPOPmN3WgKOuGZ22HSlAVTu+88w4ef/xxbN26FZmZmdi8eTPKyspQV1eHhISEPv0//fRTzJkzB8XFxfjhD3+It99+Gy+++CIOHz6MKVOm+P28gCqcOKseERER3UK9Zzy6e7xLuDbUWywN4L4pIQScboFupxv2a4t33QO70w29JgSRYWqYosOCYrY7u9ONk43tOPFVB1wegTC1Ch7hvUzUanfJf3baXbA6XLA5vEWkzeFGiAoIVamgDpEQGqKCOsS7rpIkOFze76Orx+X9nq8rWCXJ+9iBxMgwJERpkRgVhvhILSTA+126vN+tfImhALqd3rN5Hddi6na6YYrWIcWgx13JsZg3zYTRMTq0WO041diBhtYuXGztwsXWbly82oUWqwNOtwdut0BsuAYJkVqEqCS0dXnPIrV1Ofu9rPV60To11CESOrpdA+oPeAux242RSLl2aalKJaGj24nLnQ643EJ+GHbvJaNdPV/vf+2GHyBGP7BLZr8rQVU4ZWZmYubMmfjzn/8MAPB4PEhOTsaqVauwdu3aPv0XL14Mm82GXbt2ydvuueceTJ8+HVu3bvX7eSyciIiIiOhW6i1YNSG+l+AFCiEEunrcctHSWxQ73R5E67yX8UXrfAtsh8tbEP735YoOlwdWuxM2hxsxevUNHzA+EB6PgPQdPVJhMAZTGyh67rqnpwc1NTUoKiqSt6lUKmRnZ6O6urrf11RXV2PNmjU+23JycrBz587vMlQiIiIion6pr52VClSSJHkfrTCIy1a1oSH4Lq9yDcYHRStaOF2+fBlutxuJib5PXk9MTMSZM2f6fY3FYum3v8Vi6be/w+GAw/H1bDUdHR399iMiIiIiIrqRwC2Nb5Hi4mJER0fLS3JystIhERERERFRkFG0cDIYDAgJCUFzc7PP9ubmZhiNxn5fYzQaB9W/qKgI7e3t8nLx4sVbEzwREREREY0YihZOGo0GGRkZqKyslLd5PB5UVlbCbDb3+xqz2ezTHwAqKipu2F+r1SIqKspnCSh6vXchIiIiIqKApfiDDdasWYOCggLMmDEDs2bNwubNm2Gz2bB06VIAwOOPP47Ro0ejuLgYALB69Wrcf//9+P3vf4/58+ejtLQUhw4dwmuvvabkbnwz4eHemfWIiIiIiCigKV44LV68GJcuXcKGDRtgsVgwffp07NmzR54AoqGhASrV1yfG7r33Xrz99tt47rnnsG7dOqSmpmLnzp0DeoYTERERERHRN6H4c5yGWkA9x4mIiIiIiBQzmNpg2M+qF9DsdmD+fO9itysdDRERERER3YDil+qNaG43sHv31+tERERERBSQeMaJiIiIiIjIDxZOREREREREfrBwIiIiIiIi8oOFExERERERkR8snIiIiIiIiPwYcbPq9T62qqOjQ+FIANhsX693dHBmPSIiIiKiIdRbEwzk0bYjrnCyWq0AgOTkZIUjuU5SktIREBERERGNSFarFdHR0TftI4mBlFfDiMfjQWNjIyIjIyFJktLhoKOjA8nJybh48aLfpxVTcGBOhyfmdXhiXocn5nV4Yl6Hn0DIqRACVqsVSUlJUKlufhfTiDvjpFKpMGbMGKXD6CMqKooHgWGGOR2emNfhiXkdnpjX4Yl5HX6Uzqm/M029ODkEERERERGRHyyciIiIiIiI/GDhpDCtVouNGzdCq9UqHQrdIszp8MS8Dk/M6/DEvA5PzOvwE2w5HXGTQxAREREREQ0WzzgRERERERH5wcKJiIiIiIjIDxZOREREREREfrBwIiIiIiIi8oOFk4K2bNmC8ePHIywsDJmZmfjss8+UDokGYdOmTZAkyWe544475Ha73Y7CwkKMGjUKERERWLRoEZqbmxWMmPrz8ccf46GHHkJSUhIkScLOnTt92oUQ2LBhA0wmE3Q6HbKzs3H27FmfPq2trcjPz0dUVBRiYmLwi1/8Ap2dnUO4F/Tf/OV0yZIlfcZubm6uTx/mNPAUFxdj5syZiIyMREJCAhYuXIi6ujqfPgM57jY0NGD+/PnQ6/VISEjAM888A5fLNZS7QtcMJKcPPPBAn/G6fPlynz7MaWApKSnBtGnT5Ifams1mlJeXy+3BPE5ZOCnknXfewZo1a7Bx40YcPnwY6enpyMnJQUtLi9Kh0SBMnjwZTU1N8vLJJ5/Ibb/61a/w73//G2VlZaiqqkJjYyMeeeQRBaOl/thsNqSnp2PLli39tr/00kv405/+hK1bt+LgwYMIDw9HTk4O7Ha73Cc/Px8nT55ERUUFdu3ahY8//hjLli0bql2g6/jLKQDk5ub6jN3t27f7tDOngaeqqgqFhYU4cOAAKioq4HQ6MXfuXNhsNrmPv+Ou2+3G/Pnz0dPTg08//RT/+Mc/sG3bNmzYsEGJXRrxBpJTAHjiiSd8xutLL70ktzGngWfMmDF44YUXUFNTg0OHDuHBBx/EggULcPLkSQBBPk4FKWLWrFmisLBQ/tntdoukpCRRXFysYFQ0GBs3bhTp6en9trW1tQm1Wi3KysrkbadPnxYARHV19RBFSIMFQOzYsUP+2ePxCKPRKF5++WV5W1tbm9BqtWL79u1CCCFOnTolAIjPP/9c7lNeXi4kSRJfffXVkMVO/bs+p0IIUVBQIBYsWHDD1zCnwaGlpUUAEFVVVUKIgR13d+/eLVQqlbBYLHKfkpISERUVJRwOx9DuAPVxfU6FEOL+++8Xq1evvuFrmNPgEBsbK/72t78F/TjlGScF9PT0oKamBtnZ2fI2lUqF7OxsVFdXKxgZDdbZs2eRlJSECRMmID8/Hw0NDQCAmpoaOJ1OnxzfcccdGDt2LHMcROrr62GxWHzyGB0djczMTDmP1dXViImJwYwZM+Q+2dnZUKlUOHjw4JDHTAOzb98+JCQkIC0tDStWrMCVK1fkNuY0OLS3twMA4uLiAAzsuFtdXY2pU6ciMTFR7pOTk4OOjg75t+GknOtz2uutt96CwWDAlClTUFRUhK6uLrmNOQ1sbrcbpaWlsNlsMJvNQT9OQxX99BHq8uXLcLvdPn8hACAxMRFnzpxRKCoarMzMTGzbtg1paWloamrC888/j9mzZ+PEiROwWCzQaDSIiYnxeU1iYiIsFosyAdOg9eaqv7Ha22axWJCQkODTHhoairi4OOY6QOXm5uKRRx5BSkoKzp8/j3Xr1iEvLw/V1dUICQlhToOAx+PBL3/5S9x3332YMmUKAAzouGuxWPodz71tpJz+cgoAP/3pTzFu3DgkJSXh2LFjePbZZ1FXV4d//etfAJjTQHX8+HGYzWbY7XZERERgx44dmDRpEmpra4N6nLJwIvqG8vLy5PVp06YhMzMT48aNwz//+U/odDoFIyOim3n00Ufl9alTp2LatGm47bbbsG/fPmRlZSkYGQ1UYWEhTpw44XNfKQW3G+X0v+8tnDp1KkwmE7KysnD+/HncdtttQx0mDVBaWhpqa2vR3t6Od999FwUFBaiqqlI6rG+Nl+opwGAwICQkpM8MIs3NzTAajQpFRd9WTEwMbr/9dpw7dw5GoxE9PT1oa2vz6cMcB5feXN1srBqNxj6TurhcLrS2tjLXQWLChAkwGAw4d+4cAOY00K1cuRK7du3CRx99hDFjxsjbB3LcNRqN/Y7n3jZSxo1y2p/MzEwA8BmvzGng0Wg0mDhxIjIyMlBcXIz09HT88Y9/DPpxysJJARqNBhkZGaisrJS3eTweVFZWwmw2KxgZfRudnZ04f/48TCYTMjIyoFarfXJcV1eHhoYG5jiIpKSkwGg0+uSxo6MDBw8elPNoNpvR1taGmpoauc/evXvh8Xjkf+ApsH355Ze4cuUKTCYTAOY0UAkhsHLlSuzYsQN79+5FSkqKT/tAjrtmsxnHjx/3KYwrKioQFRWFSZMmDc2OkMxfTvtTW1sLAD7jlTkNfB6PBw6HI/jHqaJTU4xgpaWlQqvVim3btolTp06JZcuWiZiYGJ8ZRCiwPfXUU2Lfvn2ivr5e7N+/X2RnZwuDwSBaWlqEEEIsX75cjB07Vuzdu1ccOnRImM1mYTabFY6arme1WsWRI0fEkSNHBADxyiuviCNHjogvvvhCCCHECy+8IGJiYsR7770njh07JhYsWCBSUlJEd3e3/B65ubnirrvuEgcPHhSffPKJSE1NFY899phSuzTi3SynVqtVPP3006K6ulrU19eLDz/8UNx9990iNTVV2O12+T2Y08CzYsUKER0dLfbt2yeamprkpaurS+7j77jrcrnElClTxNy5c0Vtba3Ys2ePiI+PF0VFRUrs0ojnL6fnzp0Tv/71r8WhQ4dEfX29eO+998SECRPEnDlz5PdgTgPP2rVrRVVVlaivrxfHjh0Ta9euFZIkiQ8++EAIEdzjlIWTgl599VUxduxYodFoxKxZs8SBAweUDokGYfHixcJkMgmNRiNGjx4tFi9eLM6dOye3d3d3iyeffFLExsYKvV4vHn74YdHU1KRgxNSfjz76SADosxQUFAghvFOSr1+/XiQmJgqtViuysrJEXV2dz3tcuXJFPPbYYyIiIkJERUWJpUuXCqvVqsDekBA3z2lXV5eYO3euiI+PF2q1WowbN0488cQTfX5pxZwGnv5yCkC88cYbcp+BHHcvXLgg8vLyhE6nEwaDQTz11FPC6XQO8d6QEP5z2tDQIObMmSPi4uKEVqsVEydOFM8884xob2/3eR/mNLD8/Oc/F+PGjRMajUbEx8eLrKwsuWgSIrjHqSSEEEN3fouIiIiIiCj48B4nIiIiIiIiP1g4ERERERER+cHCiYiIiIiIyA8WTkRERERERH6wcCIiIiIiIvKDhRMREREREZEfLJyIiIiIiIj8YOFERER0E5IkYefOnUqHQURECmPhREREAWvJkiWQJKnPkpubq3RoREQ0woQqHQAREdHN5Obm4o033vDZptVqFYqGiIhGKp5xIiKigKbVamE0Gn2W2NhYAN7L6EpKSpCXlwedTocJEybg3Xff9Xn98ePH8eCDD0Kn02HUqFFYtmwZOjs7ffq8/vrrmDx5MrRaLUwmE1auXOnTfvnyZTz88MPQ6/VITU3F+++/L7ddvXoV+fn5iI+Ph06nQ2pqap9Cj4iIgh8LJyIiCmrr16/HokWLcPToUeTn5+PRRx/F6dOnAQA2mw05OTmIjY3F559/jrKyMnz44Yc+hVFJSQkKCwuxbNkyHD9+HO+//z4mTpzo8xnPP/88fvKTn+DYsWOYN28e8vPz0draKn/+qVOnUF5ejtOnT6OkpAQGg2HovgAiIhoSkhBCKB0EERFRf5YsWYI333wTYWFhPtvXrVuHdevWQZIkLF++HCUlJXLbPffcg7vvvht/+ctf8Ne//hXPPvssLl68iPDwcADA7t278dBDD6GxsRGJiYkYPXo0li5dit/+9rf9xiBJEp577jn85je/AeAtxiIiIlBeXo7c3Fz86Ec/gsFgwOuvv/4dfQtERBQIeI8TEREFtO9///s+hREAxMXFyetms9mnzWw2o7a2FgBw+vRppKeny0UTANx3333weDyoq6uDJElobGxEVlbWTWOYNm2avB4eHo6oqCi0tLQAAFasWIFFixbh8OHDmDt3LhYuXIh77733G+0rEREFLhZOREQU0MLDw/tcOner6HS6AfVTq9U+P0uSBI/HAwDIy8vDF198gd27d6OiogJZWVkoLCzE7373u1seLxERKYf3OBERUVA7cOBAn5/vvPNOAMCdd96Jo0ePwmazye379++HSqVCWloaIiMjMX78eFRWVn6rGOLj41FQUIA333wTmzdvxmuvvfat3o+IiAIPzzgREVFAczgcsFgsPttCQ0PlCRjKysowY8YMfO9738Nbb72Fzz77DH//+98BAPn5+di4cSMKCgqwadMmXLp0CatWrcLPfvYzJCYmAgA2bdqE5cuXIyEhAXl5ebBardi/fz9WrVo1oPg2bNiAjIwMTJ48GQ6HA7t27ZILNyIiGj5YOBERUUDbs2cPTCaTz7a0tDScOXMGgHfGu9LSUjz55JMwmUzYvn07Jk2aBADQ6/X4z3/+g9WrV2PmzJnQ6/VYtGgRXnnlFfm9CgoKYLfb8Yc//AFPP/00DAYDfvzjHw84Po1Gg6KiIly4cAE6nQ6zZ89GaWnpLdhzIiIKJJxVj4iIgpYkSdixYwcWLlyodChERDTM8R4nIiIiIiIiP1g4ERERERER+cF7nIiIKGjxanMiIhoqPONERERERETkBwsnIiIiIiIiP1g4ERERERER+cHCiYiIiIiIyA8WTkRERERERH6wcCIiIiIiIvKDhRMREREREZEfLJyIiIiIiIj8YOFERERERETkx/8DjA9yZ5xPb2EAAAAASUVORK5CYII=" }, "metadata": {}, "output_type": "display_data" } ], "execution_count": 7 }, { "metadata": {}, "cell_type": "markdown", "source": [ "As one might be able to tell from the above code, the only two things that changed was (1) we need to initialize/use data that has a valid global feature and (2) we need to specify how many global features we are adding to the model.\n", "\n", "If global features are available, it is worth adding them! " ], "id": "985e31e7a19e9a43" }, { "metadata": {}, "cell_type": "markdown", "source": "", "id": "ef730a00f5d16399" }, { "metadata": {}, "cell_type": "markdown", "source": "## BOHB and Hyperparameter Optimization", "id": "95562d59fd033945" }, { "metadata": {}, "cell_type": "markdown", "source": [ "In this second part of the advanced demonstration, we will have a look at hyperparameter optimization, how GraPE-Chem fits in and Ray-Tune. Note that for this, we need to install the packages:\n", "\n", "``ray``, ``ConfigSpace==0.4.18`` and ``hpbandster==0.7.4``.\n", "\n", "Let us briefly review what the core of the BOHB algorithm is. Essentially, it consists of two parts: Bayesian Optimization [3] (BO-) and HyperBand [4] (-HB), each acting as the search algorithm and a trial scheduler respectively. Bayesian optimization leverages Gaussian processes to sample the search space in a 'smart' way that optimizes the evaluation metric, and while it is very powerful, it can take a long time. To offset this, BOHB adds HyperBand, which is a bandit-based trial scheduler, capable of terminating and restarting trials to maximize trial run-time efficiency. Together, these two algorithm profit from each others strengths.\n", "\n", "\n", "For more information on the algorithm itself please see their GitHub repo ([github](https://github.com/automl/HpBandSter.git)) or their blog post reviewing their paper ([blog-post](https://www.automl.org/blog_bohb/))." ], "id": "f606e6fe49a7a5c0" }, { "metadata": {}, "cell_type": "markdown", "source": [ "### Ray Tune\n", "\n", "Ray (https://github.com/ray-project/ray) and specifically Ray Tune is a package offers streamlined hyperparameter optimization. For hyperparameter optimization using it, we need three things:\n", "* a parameter search space\n", "* an objective function which contains training and validation\n", "* a ray tuner\n", "\n", "For more information on how to use BOHB with ray-tune please check out ([using BOHB](https://docs.ray.io/en/latest/tune/examples/bohb_example.html)) and ([using checkpoints](https://docs.ray.io/en/latest/train/user-guides/checkpoints.html#train-checkpointing)).\n", "\n", "The model we will be using is AFP and the dataset is FreeSolv. As for hyperparameters, let us optimize the learning rate, the hidden (node) representation size and the number of hidden output (MLP) layers.\n", "\n", "Let us start with defining the search space:" ], "id": "d1268f7fed6e3039" }, { "metadata": { "ExecuteTime": { "end_time": "2024-06-04T14:15:43.449991Z", "start_time": "2024-06-04T14:15:43.282660Z" } }, "cell_type": "code", "source": [ "import ConfigSpace as CS\n", "config_space = CS.ConfigurationSpace()\n", "config_space.add_hyperparameter(CS.UniformIntegerHyperparameter(\"mlp_out\", lower=1, upper=5))\n", "config_space.add_hyperparameter(CS.UniformIntegerHyperparameter(\"gnn_hidden_dim\", lower=32, upper=256))\n", "config_space.add_hyperparameter(CS.UniformFloatHyperparameter('initial_lr', lower=1e-5, upper=1e-1));" ], "id": "29fd10bf0ed254c9", "outputs": [], "execution_count": 8 }, { "metadata": {}, "cell_type": "markdown", "source": "Now we need to define an objective function. Specifically, this function needs to (1) take a configuration dictionary ``config`` holding the trial hyperparameters, (2) load a model based on that config-dictionary and (3) load the correct data. All of this needs to happen **inside** the function, as Tune will need to load multiple different instances of data and models.", "id": "51dbf6a6512ba9ba" }, { "metadata": { "ExecuteTime": { "end_time": "2024-06-04T14:15:43.463047Z", "start_time": "2024-06-04T14:15:43.450895Z" } }, "cell_type": "code", "source": [ "import os\n", "import tempfile\n", "from grape_chem.models import AFP\n", "from grape_chem.datasets import FreeSolv\n", "from grape_chem.utils import return_hidden_layers, train_epoch, val_epoch, set_seed\n", "from torch_geometric.loader import DataLoader\n", "from ray.train import Checkpoint\n", "\n", "# Seed everything\n", "set_seed(42)\n", "\n", "def trainable(config: dict, device:torch.device):\n", " \"\"\" The trainable for Ray-Tune.\n", "\n", " Parameters\n", " -----------\n", " config: dict\n", " A ConfigSpace dictionary adhering to the required parameters in the trainable. Defines the search space of the HO.\n", " device: torch.device\n", " \"\"\"\n", " \n", " ################ load the data ##############\n", " data = FreeSolv()\n", " train_set, val_set, _ = data.split_and_scale(scale=True, split_type='random')\n", " train_data = DataLoader(train_set, batch_size = 300)\n", " val_data = DataLoader(val_set, batch_size = 300)\n", " \n", " ################ load the model ##############\n", " \n", " # Get mlp hidden layers\n", " mlp = return_hidden_layers(config['mlp_out'])\n", " \n", " # Define the model\n", " model = AFP(node_in_dim=data.num_node_features,edge_in_dim=data.num_edge_features, hidden_dim=config['gnn_hidden_dim'], mlp_out_hidden=mlp)\n", " model.to(device=device)\n", "\n", " \n", " # We define training stuff\n", " optimizer = torch.optim.Adam(model.parameters(), lr=config['initial_lr'], weight_decay=1e-6)\n", " early_Stopper = EarlyStopping(patience=30, model_name='random', skip_save=True)\n", " scheduler = lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.999, min_lr=1e-10, patience=10)\n", " loss_function = torch.nn.functional.l1_loss\n", "\n", " iterations = 300\n", "\n", " start_epoch = 0\n", " \n", " # HyperBand uses checkpoint, so we need to check whether to load one\n", " checkpoint = train.get_checkpoint()\n", "\n", " if checkpoint:\n", " with checkpoint.as_directory() as checkpoint_dir:\n", " model_state_dict = torch.load(\n", " os.path.join(checkpoint_dir, \"model.pt\"),\n", " # map_location=..., # Load onto a different device if needed.\n", " )\n", " model.module.load_state_dict(model_state_dict)\n", " optimizer.load_state_dict(\n", " torch.load(os.path.join(checkpoint_dir, \"optimizer.pt\"))\n", " )\n", " start_epoch = (\n", " torch.load(os.path.join(checkpoint_dir, \"extra_state.pt\"))[\"epoch\"] + 1\n", " )\n", " \n", " model.train()\n", "\n", " for i in range(start_epoch, iterations):\n", " # We take a training step\n", " train_loss = train_epoch(model=model, loss_func=loss_function, optimizer=optimizer,train_loader=train_data, device=device)\n", " # Then we validate that step\n", " val_loss = val_epoch(model=model, loss_func=loss_function, val_loader=val_data, device=device)\n", " scheduler.step(val_loss)\n", " \n", " # We check if we reached early stopping, and if so break out of the loop\n", " early_Stopper(val_loss=val_loss, model=model)\n", " if early_Stopper.stop:\n", " train.report({\"mae_loss\": val_loss})\n", " break\n", " \n", " with tempfile.TemporaryDirectory() as temp_checkpoint_dir:\n", " checkpoint = None\n", " \n", " # We save a checkpoint if we don't early stop and are on n*15 epoch\n", " should_checkpoint = i % config.get(\"checkpoint_freq\", 15) == 0\n", " # In standard DDP training, where the model is the same across all ranks,\n", " # only the global rank 0 worker needs to save and report the checkpoint\n", " if train.get_context().get_world_rank() == 0 and should_checkpoint:\n", " # === Make sure to save all state needed for resuming training ===\n", " torch.save(\n", " model.module.state_dict(), # NOTE: Unwrap the model.\n", " os.path.join(temp_checkpoint_dir, \"model.pt\"),\n", " )\n", " torch.save(\n", " optimizer.state_dict(),\n", " os.path.join(temp_checkpoint_dir, \"optimizer.pt\"),\n", " )\n", " torch.save(\n", " {\"epoch\": i},\n", " os.path.join(temp_checkpoint_dir, \"extra_state.pt\"),\n", " )\n", " # ================================================================\n", " checkpoint = Checkpoint.from_directory(temp_checkpoint_dir)\n", " \n", " # We report the training criteria\n", " train.report({\"mae_loss\": val_loss}, checkpoint=checkpoint)" ], "id": "2fbbef80356c2eee", "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "[W ParallelNative.cpp:230] Warning: Cannot set number of intraop threads after parallel work has started or after set_num_threads call when using native parallel backend (function set_num_threads)\n" ] } ], "execution_count": 9 }, { "metadata": {}, "cell_type": "markdown", "source": "The warning above is because we are working in the jupyter environment. The final building block to optimize is the ``Tuner``, essentially the object that controls the training procedure:", "id": "fef2f73ac24b60dd" }, { "metadata": { "ExecuteTime": { "end_time": "2024-06-04T14:15:43.968540Z", "start_time": "2024-06-04T14:15:43.464553Z" } }, "cell_type": "code", "source": [ "from functools import partial\n", "from ray import tune, train\n", "from ray.tune.search.bohb import TuneBOHB\n", "from ray.tune.schedulers.hb_bohb import HyperBandForBOHB\n", "\n", "if torch.cuda.is_available():\n", " device = torch.device(\"cuda\")\n", " gpu = 1\n", "else:\n", " device = torch.device(\"cpu\")\n", " gpu = 0\n", " \n", "# Partially initialize the trainable\n", "my_trainable = partial(trainable, device=device)\n", "\n", "# Give the tuner CPU and GPU resources\n", "trainable_with_resources = tune.with_resources(my_trainable, {\"cpu\":1, \"gpu\":gpu})\n", "\n", "### Define search algorithm to be BOHB\n", "algo = TuneBOHB(config_space,mode='min', metric=\"mae_loss\",)\n", "\n", "## Get the trial control algorithm\n", "scheduler = HyperBandForBOHB(\n", " time_attr=\"training_iteration\",\n", " max_t=10, # The iterations allowed per instance\n", " )\n", "\n", "n_samples = 5 # These are the number of trials, ie. we should increase this for better results.\n", "\n", "## Initialize the tuner\n", "tuner = tune.Tuner(trainable_with_resources,\n", " tune_config=tune.TuneConfig(\n", " scheduler=scheduler,\n", " search_alg=algo,\n", " mode='min',\n", " metric=\"mae_loss\",\n", " num_samples=n_samples),\n", " run_config=train.RunConfig(\n", " name=\"bo_exp\",\n", " stop={\"training_iteration\": 100}),\n", ")" ], "id": "2281501a0af68c06", "outputs": [], "execution_count": 10 }, { "metadata": {}, "cell_type": "markdown", "source": [ "That's it! The above code is (mostly) dataset and model agnostic, so we can freely change them around. Furthermore, we can either run this locally or remote (HPC) and scale it up as much as we want. But we have to be a bit careful if we want to switch out the algorithm or scheduler, as this will change some small details.\n", "\n", "Let us run the optimizer:" ], "id": "c9aec927c299929" }, { "metadata": {}, "cell_type": "code", "source": "result = tuner.fit(); # We suppress the output because it is quite long, but feel free to have a look yourself.", "id": "f10b91d0d5b77ea5", "execution_count": 11, "outputs": [ { "data": { "text/plain": [ "" ], "text/html": [ "
\n", "
\n", "
\n", "

Tune Status

\n", " \n", "\n", "\n", "\n", "\n", "\n", "
Current time:2024-06-04 16:16:18
Running for: 00:00:31.80
Memory: 11.2/16.0 GiB
\n", "
\n", "
\n", "
\n", "

System Info

\n", " Using HyperBand: num_stopped=4 total_brackets=1
Round #0:
Bracket(Max Size (n)=1, Milestone (r)=9, completed=100.0%): {TERMINATED: 5}
Logical resource usage: 1.0/8 CPUs, 0/0 GPUs\n", "
\n", " \n", "
\n", "
\n", "
\n", "

Trial Status

\n", " \n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
Trial name status loc gnn_hidden_dim initial_lr mlp_out iter total time (s) mae_loss
trainable_3bf4497dTERMINATED127.0.0.1:16513 120 0.00718788 2 9 2.37005 0.55558
trainable_7c881cfaTERMINATED127.0.0.1:16507 194 0.0731289 2 3 1.41682 0.988556
trainable_d96d6299TERMINATED127.0.0.1:16490 193 0.0427163 5 1 1.76742 36.4843
trainable_a9973e9dTERMINATED127.0.0.1:16492 82 0.0604678 5 1 1.5057 297.454
trainable_017184c1TERMINATED127.0.0.1:16510 120 0.0113299 2 3 1.13241 0.832729
\n", "
\n", "
\n", "\n" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stderr", "output_type": "stream", "text": [ "\u001B[36m(func pid=16485)\u001B[0m Downloading https://deepchemdata.s3-us-west-1.amazonaws.com/datasets/SAMPL.csv\n", "\u001B[36m(func pid=16485)\u001B[0m Processing...\n", "\u001B[36m(func pid=16485)\u001B[0m Done!\n", "\u001B[36m(func pid=16490)\u001B[0m Downloading https://deepchemdata.s3-us-west-1.amazonaws.com/datasets/SAMPL.csv\u001B[32m [repeated 2x across cluster] (Ray deduplicates logs by default. Set RAY_DEDUP_LOGS=0 to disable log deduplication, or see https://docs.ray.io/en/master/ray-observability/user-guides/configure-logging.html#log-deduplication for more options.)\u001B[0m\n", "\u001B[36m(func pid=16490)\u001B[0m Processing...\u001B[32m [repeated 2x across cluster]\u001B[0m\n", "\u001B[36m(func pid=16490)\u001B[0m Done!\u001B[32m [repeated 2x across cluster]\u001B[0m\n", "\u001B[36m(func pid=16503)\u001B[0m Downloading https://deepchemdata.s3-us-west-1.amazonaws.com/datasets/SAMPL.csv\u001B[32m [repeated 2x across cluster]\u001B[0m\n", "\u001B[36m(func pid=16503)\u001B[0m Processing...\u001B[32m [repeated 2x across cluster]\u001B[0m\n", "\u001B[36m(func pid=16492)\u001B[0m Done!\n", "\u001B[36m(func pid=16503)\u001B[0m Done!\n", "2024-06-04 16:16:06,231\tINFO hyperband.py:543 -- Restoring from a previous point in time. Previous=1; Now=1\n", "2024-06-04 16:16:09,085\tINFO hyperband.py:543 -- Restoring from a previous point in time. Previous=1; Now=1\n", "2024-06-04 16:16:11,995\tINFO hyperband.py:543 -- Restoring from a previous point in time. Previous=1; Now=1\n", "2024-06-04 16:16:16,912\tINFO hyperband.py:543 -- Restoring from a previous point in time. Previous=3; Now=1\n", "2024-06-04 16:16:18,292\tWARNING experiment_state.py:205 -- Experiment state snapshotting has been triggered multiple times in the last 5.0 seconds. A snapshot is forced if `CheckpointConfig(num_to_keep)` is set, and a trial has checkpointed >= `num_to_keep` times since the last snapshot.\n", "You may want to consider increasing the `CheckpointConfig(num_to_keep)` or decreasing the frequency of saving checkpoints.\n", "You can suppress this error by setting the environment variable TUNE_WARN_EXCESSIVE_EXPERIMENT_CHECKPOINT_SYNC_THRESHOLD_S to a smaller value than the current threshold (5.0).\n", "2024-06-04 16:16:18,294\tINFO tune.py:1007 -- Wrote the latest version of all result files and experiment state to '/Users/faerte/ray_results/bo_exp' in 0.0050s.\n", "2024-06-04 16:16:18,299\tINFO tune.py:1039 -- Total run time: 31.83 seconds (31.80 seconds for the tuning loop).\n" ] } ] }, { "metadata": { "ExecuteTime": { "end_time": "2024-06-04T14:16:18.324067Z", "start_time": "2024-06-04T14:16:18.315952Z" } }, "cell_type": "code", "source": "print('Best config is: ', result.get_best_result().config)", "id": "6c5c92d57af25b1b", "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Best config is: {'gnn_hidden_dim': 120, 'initial_lr': 0.007187876555629309, 'mlp_out': 2}\n" ] } ], "execution_count": 12 }, { "metadata": {}, "cell_type": "markdown", "source": "And that is our best set of hyperparameters for this (small) set of trials! Like mentioned, we expect the result to get better and better (up to a certain point) as we increase the number of trials.", "id": "fee3cc6089126e" }, { "metadata": {}, "cell_type": "markdown", "source": "", "id": "bb1a9fc33984d430" }, { "metadata": {}, "cell_type": "markdown", "source": [ "-----\n", "\n", "## References:\n", "\n", "[1] Falkner, S., Klein, A., & Hutter, F. (2018). Bohb: Robust and efficient hyperparameter optimization at scale.\n", "\n", "[2] Na, G. S., Kim, H. W., & Chang, H. (2020). Costless performance improvement in machine learning for graph-based molecular analysis [PMID: 31928003]. Journal of Chemical Information and Modeling, 60 (3), 1137–1145. https://doi.org/10.1021/acs.jcim.9b00816\n", "\n", "[3] Shahriari, B., Swersky, K., Wang, Z., Adams, R. P., & de Freitas, N. (2016). Taking the human out of the loop: A review of bayesian optimization. Proceedings of the IEEE, 104 (1), 148–175. https://doi.org/10.1109/JPROC.2015.2494218\n", "\n", "[4] Li, L., Jamieson, K., DeSalvo, G., Rostamizadeh, A., & Talwalkar, A. (2018). Hyperband: A novel bandit-based approach to hyperparameter optimization." ], "id": "7fd5a2ef46408147" }, { "metadata": {}, "cell_type": "markdown", "source": [ "----\n", "Extra Code to generate PDFs:" ], "id": "97202b64368dbb64" }, { "metadata": { "ExecuteTime": { "end_time": "2024-06-10T10:04:47.283922Z", "start_time": "2024-06-10T10:04:39.782546Z" } }, "cell_type": "code", "source": [ "#PDF conversion code\n", "!export PATH=/Library/TeX/texbin:$PATH\n", "!jupyter nbconvert 'Advanced GraPE-Chem Demonstration'.ipynb --to pdf --no-prompt" ], "id": "4e462eec47ba599c", "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[NbConvertApp] Converting notebook Advanced GraPE-Chem Demonstration.ipynb to pdf\r\n", "[NbConvertApp] Support files will be in Advanced GraPE-Chem Demonstration_files/\r\n", "[NbConvertApp] Making directory ./Advanced GraPE-Chem Demonstration_files\r\n", "[NbConvertApp] Writing 64745 bytes to notebook.tex\r\n", "[NbConvertApp] Building PDF\r\n", "[NbConvertApp] Running xelatex 3 times: ['xelatex', 'notebook.tex', '-quiet']\r\n", "[NbConvertApp] Running bibtex 1 time: ['bibtex', 'notebook']\r\n", "[NbConvertApp] WARNING | bibtex had problems, most likely because there were no citations\r\n", "[NbConvertApp] PDF successfully created\r\n", "[NbConvertApp] Writing 121333 bytes to Advanced GraPE-Chem Demonstration.pdf\r\n" ] } ], "execution_count": 1 }, { "metadata": {}, "cell_type": "code", "outputs": [], "execution_count": null, "source": "", "id": "a6497b1c3e24b343" } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.6" } }, "nbformat": 4, "nbformat_minor": 5 }